Compare commits
No commits in common. "5669a70156e8665db82916bb0ed206a28b2c7b35" and "9d4bb49713949d6e69771467e204ab551cc5a032" have entirely different histories.
5669a70156
...
9d4bb49713
@ -1,6 +1,6 @@
|
|||||||
# Soulstorm wiki frontend
|
# Soulstorm wiki frontend
|
||||||
|
|
||||||
## Tech stack:
|
## Стек технологий:
|
||||||
|
|
||||||
- react (mix of classes and functions)
|
- react (вперемешку классы и функции)
|
||||||
- typescript
|
- typescript
|
||||||
130
src/App.tsx
130
src/App.tsx
@ -1,105 +1,65 @@
|
|||||||
import './App.css';
|
import './App.css';
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {
|
import {AppBar, Container, createTheme, IconButton, ThemeProvider, Toolbar, Typography} from "@mui/material";
|
||||||
AppBar,
|
|
||||||
Box,
|
|
||||||
Container,
|
|
||||||
createTheme,
|
|
||||||
ThemeProvider,
|
|
||||||
Toolbar,
|
|
||||||
Typography,
|
|
||||||
useTheme
|
|
||||||
} from "@mui/material";
|
|
||||||
import {MyRoutes} from "./Routes";
|
import {MyRoutes} from "./Routes";
|
||||||
import { styled } from '@mui/material/styles';
|
|
||||||
|
|
||||||
// Styled components
|
|
||||||
const StyledAppBar = styled(AppBar)(({ theme }) => ({
|
|
||||||
background: 'linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%)',
|
|
||||||
boxShadow: '0 4px 20px rgba(0, 0, 0, 0.3)',
|
|
||||||
borderBottom: '1px solid rgba(255, 255, 255, 0.1)',
|
|
||||||
}));
|
|
||||||
|
|
||||||
const LogoText = styled(Typography)(({ theme }) => ({
|
|
||||||
fontSize: '1.5rem',
|
|
||||||
fontWeight: 800,
|
|
||||||
background: 'linear-gradient(135deg, #e94560 0%, #ff6b6b 100%)',
|
|
||||||
WebkitBackgroundClip: 'text',
|
|
||||||
WebkitTextFillColor: 'transparent',
|
|
||||||
letterSpacing: '-0.5px',
|
|
||||||
cursor: 'pointer',
|
|
||||||
'&:hover': {
|
|
||||||
transform: 'scale(1.05)',
|
|
||||||
transition: 'transform 0.2s ease',
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const theme = useTheme();
|
console.log(process.env);
|
||||||
|
|
||||||
const themeConfig = createTheme({
|
const steamLogin = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||||
breakpoints: {
|
(document.getElementById('submit-steam-login') as HTMLFormElement).click()
|
||||||
values: {
|
};
|
||||||
xs: 0,
|
|
||||||
sm: 600,
|
const theme = createTheme({
|
||||||
md: 900,
|
|
||||||
lg: 1320,
|
|
||||||
xl: 1536,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
palette: {
|
palette: {
|
||||||
primary: {
|
primary: {
|
||||||
main: "#1a1a2e",
|
main: "#191919",
|
||||||
},
|
|
||||||
background: {
|
|
||||||
default: '#0a0a0a',
|
|
||||||
paper: '#1a1a2e',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
typography: {
|
|
||||||
fontFamily: '"Inter", "Roboto", "Helvetica", sans-serif',
|
|
||||||
},
|
|
||||||
shape: {
|
|
||||||
borderRadius: 12,
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
MuiTableCell: {
|
|
||||||
styleOverrides: {
|
|
||||||
root: {
|
|
||||||
color: 'rgba(255, 255, 255, 0.85)',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ minHeight: '100vh', backgroundColor: '#0a0a0a' }}>
|
<div >
|
||||||
<ThemeProvider theme={themeConfig}>
|
<ThemeProvider theme={theme}>
|
||||||
<a href="/">
|
<AppBar position="static">
|
||||||
<StyledAppBar position="sticky">
|
<Toolbar>
|
||||||
<Container maxWidth="lg">
|
<IconButton
|
||||||
<Toolbar disableGutters sx={{ justifyContent: 'space-between' }}>
|
size="large"
|
||||||
{/* Left side - Logo */}
|
edge="start"
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
|
color="inherit"
|
||||||
<LogoText variant="h6" sx={{ textDecoration: 'none' }}>
|
aria-label="menu"
|
||||||
🎮 Autogenerated wiki
|
sx={{mr: 2}}
|
||||||
</LogoText>
|
>
|
||||||
</Box>
|
</IconButton>
|
||||||
|
<Typography variant="h6" component="div" sx={{flexGrow: 1}}>
|
||||||
{/* Right side - Navigation */}
|
Autogeneration wiki
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
</Typography>
|
||||||
</Box>
|
{/*<Button color="inherit" onClick={steamLogin}>
|
||||||
|
Log in through Steam
|
||||||
|
</Button>*/}
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
</Container>
|
</AppBar>
|
||||||
</StyledAppBar>
|
<Container>
|
||||||
</a>
|
|
||||||
|
|
||||||
<Container maxWidth="lg" sx={{ py: 4 }}>
|
|
||||||
<MyRoutes/>
|
<MyRoutes/>
|
||||||
</Container>
|
</Container>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
</Box>
|
|
||||||
|
|
||||||
|
<form action="https://steamcommunity.com/openid/login" method="post">
|
||||||
|
<input type="hidden" name="openid.identity"
|
||||||
|
value="http://specs.openid.net/auth/2.0/identifier_select"/>
|
||||||
|
<input type="hidden" name="openid.claimed_id"
|
||||||
|
value="http://specs.openid.net/auth/2.0/identifier_select"/>
|
||||||
|
<input type="hidden" name="openid.ns" value="http://specs.openid.net/auth/2.0"/>
|
||||||
|
<input type="hidden" name="openid.mode" value="checkid_setup"/>
|
||||||
|
<input type="hidden" name="openid.realm" value={process.env.REACT_APP_HOST_URL}/>
|
||||||
|
<input type="hidden" name="openid.return_to"
|
||||||
|
value={process.env.REACT_APP_HOST_URL + "\\login"}/>
|
||||||
|
<button id="submit-steam-login" type="submit" hidden={true}></button>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,15 +6,7 @@ import {getIcon} from "./ModifiersProvideTable";
|
|||||||
import {IMod} from "../types/Imod";
|
import {IMod} from "../types/Imod";
|
||||||
import AbilityFull from "./AbilityFull";
|
import AbilityFull from "./AbilityFull";
|
||||||
import {Irace} from "../types/Irace";
|
import {Irace} from "../types/Irace";
|
||||||
import {styled} from '@mui/material/styles';
|
|
||||||
|
|
||||||
const StyledAccordion = styled(Accordion)(({ theme }) => ({
|
|
||||||
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
||||||
borderRadius: '12px',
|
|
||||||
'&:before': { display: 'none' },
|
|
||||||
'&.Mui-expanded': { margin: '0 0 8px 0' },
|
|
||||||
}));
|
|
||||||
|
|
||||||
interface IAbilityProps {
|
interface IAbilityProps {
|
||||||
ability: IAbilityShort,
|
ability: IAbilityShort,
|
||||||
@ -26,23 +18,22 @@ function Ability(props: IAbilityProps){
|
|||||||
|
|
||||||
const ability = props.ability
|
const ability = props.ability
|
||||||
|
|
||||||
return <div className='addon-research-accordion' id={"research-" + ability.id}><StyledAccordion TransitionProps={{ unmountOnExit: true, timeout: 100 }}>
|
return <div className='addon-research-accordion' id={"research-" + ability.id}><Accordion TransitionProps={{ unmountOnExit: true, timeout: 100 }}>
|
||||||
<AccordionSummary
|
<AccordionSummary
|
||||||
expandIcon={<ExpandMore sx={{color: '#ffffff'}}/>}
|
expandIcon={<ExpandMore/>}
|
||||||
aria-controls="panel1-content"
|
aria-controls="panel1-content"
|
||||||
sx={{color: '#ffffff'}}
|
|
||||||
>
|
>
|
||||||
<span style={{fontSize: 20, color: '#ffffff'}}>
|
<span style={{fontSize: 20}}>
|
||||||
{ability.activationType === "Passive ability" ? <img className="abilityIcon" src="/images/PassiveIcon.gif"/> : <img className="abilityIcon" src={getIcon(ability.icon)}/>}
|
{ability.activationType === "Passive ability" ? <img className="abilityIcon" src="/images/PassiveIcon.gif"/> : <img className="abilityIcon" src={getIcon(ability.icon)}/>}
|
||||||
{ability.name ? ability.name : ability.fileName.charAt(0).toUpperCase() + ability.fileName.slice(1).replaceAll('_', ' ').replace('.rgd', '')}
|
{ability.name ? ability.name : ability.fileName.charAt(0).toUpperCase() + ability.fileName.slice(1).replaceAll('_', ' ').replace('.rgd', '')}
|
||||||
<i style={{fontSize: 12, color: 'rgba(255,255,255,0.5)'}}> ({ability.activationType})</i>
|
<i style={{fontSize: 12}}> ({ability.activationType})</i>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
</AccordionSummary>
|
</AccordionSummary>
|
||||||
<AccordionDetails sx={{color: 'rgba(255,255,255,0.85)'}}>
|
<AccordionDetails>
|
||||||
<AbilityFull abilityId={ability.id} mod={props.mod} race={props.race} />
|
<AbilityFull abilityId={ability.id} mod={props.mod} race={props.race} />
|
||||||
</AccordionDetails>
|
</AccordionDetails>
|
||||||
</StyledAccordion></div>
|
</Accordion></div>
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -27,7 +27,6 @@ import AvTimerOutlinedIcon from "@mui/icons-material/AvTimer";
|
|||||||
import ability from "./Ability";
|
import ability from "./Ability";
|
||||||
import AbilitySpawnedObject from "./AbilitySpawnedObject";
|
import AbilitySpawnedObject from "./AbilitySpawnedObject";
|
||||||
import DpsTable from "./DpsTable";
|
import DpsTable from "./DpsTable";
|
||||||
import {DescriptionBox} from "../commons/DescriptionBox";
|
|
||||||
|
|
||||||
interface IAbilityFullState {
|
interface IAbilityFullState {
|
||||||
ability?: IAbilityFill;
|
ability?: IAbilityFill;
|
||||||
@ -42,33 +41,16 @@ export default function AbilityFull(props: { abilityId?: number, mod: IMod, race
|
|||||||
|
|
||||||
const StyledTableCell = styled(TableCell)(({theme}) => ({
|
const StyledTableCell = styled(TableCell)(({theme}) => ({
|
||||||
[`&.${tableCellClasses.head}`]: {
|
[`&.${tableCellClasses.head}`]: {
|
||||||
backgroundColor: 'rgba(233, 69, 96, 0.15)',
|
backgroundColor: "rgb(244,244,244)",
|
||||||
fontWeight: 700,
|
|
||||||
marginRight: 'auto',
|
marginRight: 'auto',
|
||||||
marginLeft: 'auto',
|
marginLeft: 'auto',
|
||||||
paddingLeft: 10,
|
paddingLeft: 10
|
||||||
borderBottom: '2px solid rgba(233, 69, 96, 0.3)',
|
|
||||||
},
|
},
|
||||||
[`&.${tableCellClasses.body}`]: {
|
[`&.${tableCellClasses.body}`]: {
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
color: 'rgba(255, 255, 255, 0.85)',
|
|
||||||
paddingRight: 18,
|
paddingRight: 18,
|
||||||
paddingLeft: 10,
|
paddingLeft: 10
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const StyledPaper = styled(Paper)(({ theme }) => ({
|
|
||||||
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
||||||
borderRadius: '12px',
|
|
||||||
overflow: 'hidden',
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-root': {
|
|
||||||
color: 'rgba(255, 255, 255, 0.9)',
|
|
||||||
},
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-head': {
|
|
||||||
color: '#e94560',
|
|
||||||
fontWeight: 600,
|
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -108,21 +90,21 @@ export default function AbilityFull(props: { abilityId?: number, mod: IMod, race
|
|||||||
const showTargetTable = !showDpsTable && ability.abilityEnvironment == null && (ability.targetFilter.length > 0 || ability.radius !== 0)
|
const showTargetTable = !showDpsTable && ability.abilityEnvironment == null && (ability.targetFilter.length > 0 || ability.radius !== 0)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{color: 'rgba(255, 255, 255, 0.85)'}}>
|
<div>
|
||||||
<Grid2 container spacing={2}>
|
<Grid2 container spacing={2}>
|
||||||
<Grid2 size={{xs: 12}}>
|
<Grid2 size={{xs: 12}}>
|
||||||
{ability.initialDelayTime !== undefined && props.isChild === true &&
|
{ability.initialDelayTime !== undefined && props.isChild === true &&
|
||||||
<b><br/><center style={{color: 'rgba(255,255,255,0.7)'}}> After {ability.initialDelayTime.toFixed(1)}s
|
<b><br/><center> After {ability.initialDelayTime.toFixed(1)}s
|
||||||
<img style={{verticalAlign: "top"}}
|
<img style={{verticalAlign: "top"}}
|
||||||
src="/images/Time_icon.webp"/></center></b>}
|
src="/images/Time_icon.webp"/></center></b>}
|
||||||
</Grid2>
|
</Grid2>
|
||||||
<Grid2 size={{xs: 12, md: 4}}>
|
<Grid2 size={{xs: 12, md: 4}}>
|
||||||
<TableContainer component={StyledPaper} elevation={0}>
|
<TableContainer component={Paper}>
|
||||||
<Table size="small" aria-label="a dense table">
|
<Table size="small" aria-label="a dense table">
|
||||||
<TableBody id="unit-stats-table">
|
<TableBody id="unit-stats-table">
|
||||||
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
<TableRow>
|
||||||
<TableCell component="th" scope="row">Affected on</TableCell>
|
<TableCell component="th" scope="row">Affected on</TableCell>
|
||||||
<TableCell>{ability.areaFilter}</TableCell>
|
<TableCell component="th" scope="row">{ability.areaFilter}</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
{props.isChild !== true && (ability.costPower !== undefined && ability.costPower > 0 ||
|
{props.isChild !== true && (ability.costPower !== undefined && ability.costPower > 0 ||
|
||||||
ability.costRequisition !== undefined && ability.costRequisition > 0 ||
|
ability.costRequisition !== undefined && ability.costRequisition > 0 ||
|
||||||
@ -132,7 +114,7 @@ export default function AbilityFull(props: { abilityId?: number, mod: IMod, race
|
|||||||
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
>
|
>
|
||||||
<TableCell component="th" scope="row">Cost</TableCell>
|
<TableCell component="th" scope="row">Cost</TableCell>
|
||||||
<TableCell>
|
<TableCell component="th" scope="row">
|
||||||
{ability.costRequisition !== undefined && ability.costRequisition > 0 &&
|
{ability.costRequisition !== undefined && ability.costRequisition > 0 &&
|
||||||
<span> <img style={{verticalAlign: "top"}}
|
<span> <img style={{verticalAlign: "top"}}
|
||||||
src="/images/Resource_requisition.gif"/>
|
src="/images/Resource_requisition.gif"/>
|
||||||
@ -154,18 +136,18 @@ export default function AbilityFull(props: { abilityId?: number, mod: IMod, race
|
|||||||
{props.isChild !== true && ability.rechargeTime !== undefined && ability.rechargeTime > 0 && ability.activation !== "On/off ability" &&
|
{props.isChild !== true && ability.rechargeTime !== undefined && ability.rechargeTime > 0 && ability.activation !== "On/off ability" &&
|
||||||
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
||||||
<TableCell component="th" scope="row">Recharge time</TableCell>
|
<TableCell component="th" scope="row">Recharge time</TableCell>
|
||||||
<TableCell>
|
<TableCell component="th" scope="row">
|
||||||
<img style={{verticalAlign: "top"}}
|
<img style={{verticalAlign: "top"}}
|
||||||
src="/images/Time_icon.webp"/>
|
src="/images/Time_icon.webp"/>
|
||||||
{ability.rechargeTime}s
|
{ability.rechargeTime}s
|
||||||
{ability.rechargeTimerGlobal && <i style={{fontSize: 10, color: 'rgba(255,255,255,0.5)'}}>global cooldown</i>}
|
{ability.rechargeTimerGlobal && <i style={{fontSize: 10}}>global cooldown</i>}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
}
|
}
|
||||||
{props.isChild !== true && ability.initialDelayTime !== undefined && ability.initialDelayTime > 0 &&
|
{props.isChild !== true && ability.initialDelayTime !== undefined && ability.initialDelayTime > 0 &&
|
||||||
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
||||||
<TableCell component="th" scope="row">Delay after cast</TableCell>
|
<TableCell component="th" scope="row">Delay after cast</TableCell>
|
||||||
<TableCell>
|
<TableCell component="th" scope="row">
|
||||||
<img style={{verticalAlign: "top"}}
|
<img style={{verticalAlign: "top"}}
|
||||||
src="/images/Time_icon.webp"/>
|
src="/images/Time_icon.webp"/>
|
||||||
{ability.initialDelayTime.toFixed(1)}s
|
{ability.initialDelayTime.toFixed(1)}s
|
||||||
@ -175,7 +157,7 @@ export default function AbilityFull(props: { abilityId?: number, mod: IMod, race
|
|||||||
{ability.durationTime !== undefined && ability.durationTime > 1.5 &&
|
{ability.durationTime !== undefined && ability.durationTime > 1.5 &&
|
||||||
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
||||||
<TableCell component="th" scope="row">Duration time</TableCell>
|
<TableCell component="th" scope="row">Duration time</TableCell>
|
||||||
<TableCell>
|
<TableCell component="th" scope="row">
|
||||||
<img style={{verticalAlign: "top"}}
|
<img style={{verticalAlign: "top"}}
|
||||||
src="/images/Time_icon.webp"/>
|
src="/images/Time_icon.webp"/>
|
||||||
{ability.durationTime.toFixed(1)}s
|
{ability.durationTime.toFixed(1)}s
|
||||||
@ -185,15 +167,15 @@ export default function AbilityFull(props: { abilityId?: number, mod: IMod, race
|
|||||||
{ability.areaEffect !== null && ability.radius !== undefined && ability.radius > 0 &&
|
{ability.areaEffect !== null && ability.radius !== undefined && ability.radius > 0 &&
|
||||||
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
||||||
<TableCell component="th" scope="row">Radius</TableCell>
|
<TableCell component="th" scope="row">Radius</TableCell>
|
||||||
<TableCell>
|
<TableCell component="th" scope="row">
|
||||||
{ability.radius.toFixed(0)} <i style={{fontSize: 10, color: 'rgba(255,255,255,0.5)'}}>{ability.areaEffect}</i>
|
{ability.radius.toFixed(0)} <i style={{fontSize: 10}}>{ability.areaEffect}</i>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
}
|
}
|
||||||
{props.isChild !== true && ability.range !== undefined && ability.areaFilter !== "Own" && ability.range > 0 &&
|
{props.isChild !== true && ability.range !== undefined && ability.areaFilter !== "Own" && ability.range > 0 &&
|
||||||
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
||||||
<TableCell component="th" scope="row">Range</TableCell>
|
<TableCell component="th" scope="row">Range</TableCell>
|
||||||
<TableCell>
|
<TableCell component="th" scope="row">
|
||||||
{ability.range.toFixed(0)}
|
{ability.range.toFixed(0)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
@ -203,19 +185,25 @@ export default function AbilityFull(props: { abilityId?: number, mod: IMod, race
|
|||||||
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
>
|
>
|
||||||
<TableCell component="th" scope="row">Throw force</TableCell>
|
<TableCell component="th" scope="row">Throw force</TableCell>
|
||||||
<TableCell>{ability.throwForceMin != 0 ? ability.throwForceMin + " - " + ability.throwForceMax : "-"}
|
<TableCell component="th"
|
||||||
|
scope="row">{ability.throwForceMin != 0 ? ability.throwForceMin + " - " + ability.throwForceMax : "-"}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>}
|
</TableRow>}
|
||||||
|
<TableRow>
|
||||||
|
|
||||||
|
</TableRow>
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</TableContainer><br/>
|
</TableContainer><br/>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
<Grid2 size={8}>
|
<Grid2 size={8}>
|
||||||
{props.isChild !== true && <DescriptionBox>{ability.description}</DescriptionBox>}
|
<div style={{whiteSpace: "pre-wrap"}}>
|
||||||
|
{props.isChild !== true && ability.description}
|
||||||
|
</div>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
{showDpsTable ?
|
{showDpsTable ?
|
||||||
<Grid2 size={12}>
|
<Grid2 size={12}>
|
||||||
{(ability.refreshTime !== undefined && ability.durationTime !== undefined && ability.refreshTime * 2 < ability.durationTime) && <i style={{color: 'rgba(255,255,255,0.7)'}}>Every <b style={{color: '#ffffff'}}>{ability.refreshTime.toFixed(1)}s</b> deal damege:</i>}
|
{(ability.refreshTime !== undefined && ability.durationTime !== undefined && ability.refreshTime * 2 < ability.durationTime) && <i>Every <b>{ability.refreshTime.toFixed(1)}s</b> deal damege:</i>}
|
||||||
<DpsTable mod={props.mod} minDamageValue={ability.minDamageValue} minDamage={ability.minDamage} maxDamage={ability.maxDamage} piercings={ability.piercings} targetFilter={ability.targetFilter} moraleDamage={ability.moraleDamage}
|
<DpsTable mod={props.mod} minDamageValue={ability.minDamageValue} minDamage={ability.minDamage} maxDamage={ability.maxDamage} piercings={ability.piercings} targetFilter={ability.targetFilter} moraleDamage={ability.moraleDamage}
|
||||||
/>
|
/>
|
||||||
</Grid2> : showTargetTable ?
|
</Grid2> : showTargetTable ?
|
||||||
@ -247,7 +235,7 @@ export default function AbilityFull(props: { abilityId?: number, mod: IMod, race
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
<TableRow>
|
||||||
<StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.InfantryLow)}</StyledTableCell>
|
<StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.InfantryLow)}</StyledTableCell>
|
||||||
<StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.InfantryMedium)}</StyledTableCell>
|
<StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.InfantryMedium)}</StyledTableCell>
|
||||||
<StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.InfantryHigh)}</StyledTableCell>
|
<StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.InfantryHigh)}</StyledTableCell>
|
||||||
@ -284,7 +272,7 @@ export default function AbilityFull(props: { abilityId?: number, mod: IMod, race
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
<TableRow>
|
||||||
<StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.VehicleLow)}</StyledTableCell>
|
<StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.VehicleLow)}</StyledTableCell>
|
||||||
<StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.VehicleMedium)}</StyledTableCell>
|
<StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.VehicleMedium)}</StyledTableCell>
|
||||||
<StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.VehicleHigh)}</StyledTableCell>
|
<StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.VehicleHigh)}</StyledTableCell>
|
||||||
@ -333,7 +321,7 @@ export default function AbilityFull(props: { abilityId?: number, mod: IMod, race
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
<TableRow>
|
||||||
<StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.InfantryLow)}</StyledTableCell>
|
<StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.InfantryLow)}</StyledTableCell>
|
||||||
<StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.InfantryMedium)}</StyledTableCell>
|
<StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.InfantryMedium)}</StyledTableCell>
|
||||||
<StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.InfantryHigh)}</StyledTableCell>
|
<StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.InfantryHigh)}</StyledTableCell>
|
||||||
@ -364,10 +352,10 @@ export default function AbilityFull(props: { abilityId?: number, mod: IMod, race
|
|||||||
<Grid2 size={{xs: 12, md: 12}}>
|
<Grid2 size={{xs: 12, md: 12}}>
|
||||||
<Required requirement={ability.requirements} modId={props.mod.id} raceId={props.race.id}/>
|
<Required requirement={ability.requirements} modId={props.mod.id} raceId={props.race.id}/>
|
||||||
</Grid2>}
|
</Grid2>}
|
||||||
{props.isChild !== true && ability.activation !== "Passive ability" && <b className="hotkey" >Hotkey: {ability.hotkey}</b>}
|
{ability.activation !== "Passive ability" && props.isChild !== true && <b className="hotkey">Hotkey: {ability.hotkey}</b>}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
} else return <div style={{color: 'rgba(255, 255, 255, 0.5)'}}>loading...</div>;
|
} else return <div>loading...</div>;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -6,8 +6,7 @@ import {
|
|||||||
TableBody,
|
TableBody,
|
||||||
TableCell, TableContainer,
|
TableCell, TableContainer,
|
||||||
TableRow,
|
TableRow,
|
||||||
Tooltip,
|
Tooltip
|
||||||
Typography
|
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import {ExpandMore} from "@mui/icons-material";
|
import {ExpandMore} from "@mui/icons-material";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
@ -22,28 +21,6 @@ import ArmorType from "./ArmorType";
|
|||||||
import Vision from "./Vision";
|
import Vision from "./Vision";
|
||||||
import Ability from "./Ability";
|
import Ability from "./Ability";
|
||||||
import DeathExplosion from "./DeathExplosion";
|
import DeathExplosion from "./DeathExplosion";
|
||||||
import {styled} from '@mui/material/styles';
|
|
||||||
import {DescriptionBox} from "../commons/DescriptionBox";
|
|
||||||
|
|
||||||
const SectionTitle = styled(Typography)(({ theme }) => ({
|
|
||||||
fontWeight: 700,
|
|
||||||
mb: 2,
|
|
||||||
fontSize: '1.25rem',
|
|
||||||
}));
|
|
||||||
|
|
||||||
const StyledPaper = styled(Paper)(({ theme }) => ({
|
|
||||||
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
||||||
borderRadius: '12px',
|
|
||||||
overflow: 'hidden',
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-root': {
|
|
||||||
color: 'rgba(255, 255, 255, 0.9)',
|
|
||||||
},
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-head': {
|
|
||||||
color: '#e94560',
|
|
||||||
fontWeight: 600,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
interface AbilityEnvironmentProps {
|
interface AbilityEnvironmentProps {
|
||||||
@ -56,14 +33,13 @@ function AbilitySpawnedObject(props: AbilityEnvironmentProps) {
|
|||||||
|
|
||||||
const abilityEnvironment = props.abilityEnvironment
|
const abilityEnvironment = props.abilityEnvironment
|
||||||
|
|
||||||
return <div style={{color: 'rgba(255, 255, 255, 0.85)'}}>
|
return <div>
|
||||||
<SectionTitle>
|
<h3> {props.abilityEnvironment.name ?? props.abilityEnvironment.filename.charAt(0).toUpperCase() + props.abilityEnvironment.filename.slice(1).replaceAll('_', ' ').replace('.rgd', '')}
|
||||||
{props.abilityEnvironment.name ?? props.abilityEnvironment.filename.charAt(0).toUpperCase() + props.abilityEnvironment.filename.slice(1).replaceAll('_', ' ').replace('.rgd', '')}
|
<i style={{fontSize: 11}}> (Spawned object)</i>
|
||||||
<i style={{fontSize: 11, color: 'rgba(255,255,255,0.5)'}}> (Spawned object)</i>
|
</h3>
|
||||||
</SectionTitle>
|
|
||||||
<Grid2 container spacing={2}>
|
<Grid2 container spacing={2}>
|
||||||
<Grid2 size={{xs: 12, md: 4}}>
|
<Grid2 size={{xs: 12, md: 4}}>
|
||||||
<TableContainer component={StyledPaper} elevation={0}>
|
<TableContainer component={Paper}>
|
||||||
<Table size="small" aria-label="a dense table">
|
<Table size="small" aria-label="a dense table">
|
||||||
<TableBody id="unit-stats-table">
|
<TableBody id="unit-stats-table">
|
||||||
{abilityEnvironment.armorType !== null &&
|
{abilityEnvironment.armorType !== null &&
|
||||||
@ -71,7 +47,7 @@ function AbilitySpawnedObject(props: AbilityEnvironmentProps) {
|
|||||||
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
>
|
>
|
||||||
<TableCell component="th" scope="row">Armor type</TableCell>
|
<TableCell component="th" scope="row">Armor type</TableCell>
|
||||||
<TableCell>
|
<TableCell component="th" scope="row">
|
||||||
{abilityEnvironment.armorType2 == null ?
|
{abilityEnvironment.armorType2 == null ?
|
||||||
<ArmorType name={abilityEnvironment.armorType.name} compact={false}/> :
|
<ArmorType name={abilityEnvironment.armorType.name} compact={false}/> :
|
||||||
<Tooltip
|
<Tooltip
|
||||||
@ -86,7 +62,7 @@ function AbilitySpawnedObject(props: AbilityEnvironmentProps) {
|
|||||||
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
>
|
>
|
||||||
<TableCell component="th" scope="row">Health</TableCell>
|
<TableCell component="th" scope="row">Health</TableCell>
|
||||||
<TableCell>
|
<TableCell component="th" scope="row">
|
||||||
<img style={{verticalAlign: "top"}}
|
<img style={{verticalAlign: "top"}}
|
||||||
src="/images/Health_icon.webp"/>
|
src="/images/Health_icon.webp"/>
|
||||||
{abilityEnvironment.health} {abilityEnvironment.healthRegeneration != null && abilityEnvironment.healthRegeneration > 0 &&
|
{abilityEnvironment.health} {abilityEnvironment.healthRegeneration != null && abilityEnvironment.healthRegeneration > 0 &&
|
||||||
@ -102,7 +78,9 @@ function AbilitySpawnedObject(props: AbilityEnvironmentProps) {
|
|||||||
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
>
|
>
|
||||||
<TableCell component="th" scope="row">Move speed</TableCell>
|
<TableCell component="th" scope="row">Move speed</TableCell>
|
||||||
<TableCell>{abilityEnvironment.moveSpeed}</TableCell>
|
<TableCell component="th" scope="row">
|
||||||
|
{abilityEnvironment.moveSpeed}
|
||||||
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
}
|
}
|
||||||
{abilityEnvironment.sightRadius != null &&
|
{abilityEnvironment.sightRadius != null &&
|
||||||
@ -110,7 +88,7 @@ function AbilitySpawnedObject(props: AbilityEnvironmentProps) {
|
|||||||
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
>
|
>
|
||||||
<TableCell component="th" scope="row">Vision</TableCell>
|
<TableCell component="th" scope="row">Vision</TableCell>
|
||||||
<TableCell>
|
<TableCell component="th" scope="row">
|
||||||
<Vision sight={abilityEnvironment.sightRadius ?? 0}
|
<Vision sight={abilityEnvironment.sightRadius ?? 0}
|
||||||
detect={abilityEnvironment.detectRadius ?? 0}/>
|
detect={abilityEnvironment.detectRadius ?? 0}/>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
@ -119,7 +97,7 @@ function AbilitySpawnedObject(props: AbilityEnvironmentProps) {
|
|||||||
{abilityEnvironment.lifetime != null &&
|
{abilityEnvironment.lifetime != null &&
|
||||||
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
||||||
<TableCell component="th" scope="row">Lifetime</TableCell>
|
<TableCell component="th" scope="row">Lifetime</TableCell>
|
||||||
<TableCell>
|
<TableCell component="th" scope="row">
|
||||||
<img style={{verticalAlign: "top"}}
|
<img style={{verticalAlign: "top"}}
|
||||||
src="/images/Time_icon.webp"/>
|
src="/images/Time_icon.webp"/>
|
||||||
{abilityEnvironment.lifetime.toFixed(0)}s
|
{abilityEnvironment.lifetime.toFixed(0)}s
|
||||||
@ -131,9 +109,9 @@ function AbilitySpawnedObject(props: AbilityEnvironmentProps) {
|
|||||||
</TableContainer>
|
</TableContainer>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
<Grid2 size={{xs: 12, md: 8}}>
|
<Grid2 size={{xs: 12, md: 8}}>
|
||||||
<DescriptionBox>
|
<div style={{whiteSpace: "pre-wrap"}}>
|
||||||
{abilityEnvironment.description}
|
{abilityEnvironment.description}
|
||||||
</DescriptionBox>
|
</div>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
{abilityEnvironment.abilities.length > 0 && <Grid2 size={12}>
|
{abilityEnvironment.abilities.length > 0 && <Grid2 size={12}>
|
||||||
{abilityEnvironment.abilities.map(a =>
|
{abilityEnvironment.abilities.map(a =>
|
||||||
|
|||||||
@ -24,29 +24,6 @@ import {IDeathExplosion} from "../types/IDeathExplosion";
|
|||||||
import Required from "./Required";
|
import Required from "./Required";
|
||||||
import ArmorTypeNames from "../types/ArmorTypeValues";
|
import ArmorTypeNames from "../types/ArmorTypeValues";
|
||||||
import DpsTable from "./DpsTable";
|
import DpsTable from "./DpsTable";
|
||||||
import {styled} from '@mui/material/styles';
|
|
||||||
|
|
||||||
const StyledAccordion = styled(Accordion)(({ theme }) => ({
|
|
||||||
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
||||||
borderRadius: '12px',
|
|
||||||
'&:before': { display: 'none' },
|
|
||||||
'&.Mui-expanded': { margin: '0 0 8px 0' },
|
|
||||||
}));
|
|
||||||
|
|
||||||
const StyledPaper = styled(Paper)(({ theme }) => ({
|
|
||||||
background: 'rgba(255, 255, 255, 0.03)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.05)',
|
|
||||||
borderRadius: '12px',
|
|
||||||
overflow: 'hidden',
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-root': {
|
|
||||||
color: 'rgba(255, 255, 255, 0.85)',
|
|
||||||
},
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-head': {
|
|
||||||
color: '#e94560',
|
|
||||||
fontWeight: 600,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
interface DeathExpProps {
|
interface DeathExpProps {
|
||||||
@ -60,37 +37,44 @@ function DeathExplosion(props: DeathExpProps) {
|
|||||||
const chanceTotalNotZero = deathExplosion.globalChance * deathExplosion.chance != 0
|
const chanceTotalNotZero = deathExplosion.globalChance * deathExplosion.chance != 0
|
||||||
|
|
||||||
return chanceTotalNotZero ?
|
return chanceTotalNotZero ?
|
||||||
<div className='addon-research-accordion' id='death-explosion'><StyledAccordion>
|
<div className='addon-research-accordion' id='death-explosion'><Accordion>
|
||||||
<AccordionSummary
|
<AccordionSummary
|
||||||
expandIcon={<ExpandMore sx={{color: '#ffffff'}}/>}
|
expandIcon={<ExpandMore/>}
|
||||||
aria-controls="panel1-content"
|
aria-controls="panel1-content"
|
||||||
sx={{color: '#ffffff'}}
|
|
||||||
>
|
>
|
||||||
<span style={{fontSize: 20, color: '#ffffff'}}>
|
<span style={{fontSize: 20}}>
|
||||||
Death Explosion
|
Death Explosion
|
||||||
</span>
|
</span>
|
||||||
</AccordionSummary>
|
</AccordionSummary>
|
||||||
<AccordionDetails sx={{color: 'rgba(255,255,255,0.85)'}}>
|
<AccordionDetails>
|
||||||
<Grid2 container spacing={2}>
|
<Grid2 container spacing={2}>
|
||||||
<Grid2 size={{xs: 12, md: 4}}>
|
<Grid2 size={{xs: 12, md: 4}}>
|
||||||
<TableContainer component={StyledPaper} elevation={0}>
|
<TableContainer component={Paper}>
|
||||||
<Table size="small" aria-label="a dense table">
|
<Table size="small" aria-label="a dense table">
|
||||||
<TableBody id="unit-stats-table">
|
<TableBody id="unit-stats-table">
|
||||||
<TableRow
|
<TableRow
|
||||||
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
>
|
>
|
||||||
<TableCell component="th" scope="row">Chance</TableCell>
|
<TableCell component="th" scope="row">Chance</TableCell>
|
||||||
<TableCell>{deathExplosion.globalChance * deathExplosion.chance}%</TableCell>
|
<TableCell component="th" scope="row">
|
||||||
|
{deathExplosion.globalChance * deathExplosion.chance}%
|
||||||
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow
|
<TableRow
|
||||||
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
>
|
>
|
||||||
<TableCell component="th" scope="row">Damage radius</TableCell>
|
<TableCell component="th" scope="row">Damage radius</TableCell>
|
||||||
<TableCell>{deathExplosion.damageRadius}</TableCell>
|
<TableCell component="th" scope="row">
|
||||||
|
{deathExplosion.damageRadius}
|
||||||
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
<TableRow
|
||||||
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
|
>
|
||||||
<TableCell component="th" scope="row">Throw force</TableCell>
|
<TableCell component="th" scope="row">Throw force</TableCell>
|
||||||
<TableCell>{deathExplosion.throwForceMin} - {deathExplosion.throwForceMax}</TableCell>
|
<TableCell component="th" scope="row">
|
||||||
|
{deathExplosion.throwForceMin} - {deathExplosion.throwForceMax}
|
||||||
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
@ -104,7 +88,7 @@ function DeathExplosion(props: DeathExpProps) {
|
|||||||
</Grid2>
|
</Grid2>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
</AccordionDetails>
|
</AccordionDetails>
|
||||||
</StyledAccordion></div> : <span></span>
|
</Accordion></div> : <span></span>
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -19,19 +19,16 @@ export default function DpsTable(props: { mod: IMod, minDamageValue?: number, mi
|
|||||||
|
|
||||||
const StyledTableCell = styled(TableCell)(({theme}) => ({
|
const StyledTableCell = styled(TableCell)(({theme}) => ({
|
||||||
[`&.${tableCellClasses.head}`]: {
|
[`&.${tableCellClasses.head}`]: {
|
||||||
backgroundColor: 'rgba(233, 69, 96, 0.15)',
|
backgroundColor: "rgb(244,244,244)",
|
||||||
fontWeight: 700,
|
|
||||||
marginRight: 'auto',
|
marginRight: 'auto',
|
||||||
marginLeft: 'auto',
|
marginLeft: 'auto',
|
||||||
paddingLeft: 10,
|
paddingLeft: 10
|
||||||
borderBottom: '2px solid rgba(233, 69, 96, 0.3)',
|
|
||||||
},
|
},
|
||||||
[`&.${tableCellClasses.body}`]: {
|
[`&.${tableCellClasses.body}`]: {
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
color: 'rgba(255, 255, 255, 0.85)',
|
|
||||||
paddingRight: 18,
|
paddingRight: 18,
|
||||||
paddingLeft: 10,
|
paddingLeft: 10
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -161,7 +158,7 @@ export default function DpsTable(props: { mod: IMod, minDamageValue?: number, mi
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
<TableRow>
|
||||||
<StyledTableCell>{getTotalDamage(vehLowPiercing)}</StyledTableCell>
|
<StyledTableCell>{getTotalDamage(vehLowPiercing)}</StyledTableCell>
|
||||||
<StyledTableCell>{getTotalDamage(vehMedPiercing)}</StyledTableCell>
|
<StyledTableCell>{getTotalDamage(vehMedPiercing)}</StyledTableCell>
|
||||||
<StyledTableCell>{getTotalDamage(vehHighPiercing)}</StyledTableCell>
|
<StyledTableCell>{getTotalDamage(vehHighPiercing)}</StyledTableCell>
|
||||||
@ -215,7 +212,7 @@ export default function DpsTable(props: { mod: IMod, minDamageValue?: number, mi
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
<TableRow>
|
||||||
<StyledTableCell>{getTotalDamage(infLowPiercing)}</StyledTableCell>
|
<StyledTableCell>{getTotalDamage(infLowPiercing)}</StyledTableCell>
|
||||||
<StyledTableCell>{getTotalDamage(infMedPiercing)}</StyledTableCell>
|
<StyledTableCell>{getTotalDamage(infMedPiercing)}</StyledTableCell>
|
||||||
<StyledTableCell>{getTotalDamage(infHighPiercing)}</StyledTableCell>
|
<StyledTableCell>{getTotalDamage(infHighPiercing)}</StyledTableCell>
|
||||||
|
|||||||
@ -6,20 +6,6 @@ import {Irace} from "../types/Irace";
|
|||||||
import {IAffectedData} from "../types/IAffectedData";
|
import {IAffectedData} from "../types/IAffectedData";
|
||||||
import {IMod} from "../types/Imod";
|
import {IMod} from "../types/Imod";
|
||||||
import AvTimerOutlinedIcon from "@mui/icons-material/AvTimer";
|
import AvTimerOutlinedIcon from "@mui/icons-material/AvTimer";
|
||||||
import {styled} from '@mui/material/styles';
|
|
||||||
import {StyledLink} from "../commons/StyledLink";
|
|
||||||
|
|
||||||
// Styled components for dark theme
|
|
||||||
const StyledPaper = styled(Paper)(({ theme }) => ({
|
|
||||||
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
||||||
borderRadius: '12px',
|
|
||||||
overflow: 'hidden',
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-root': {
|
|
||||||
color: 'rgba(255, 255, 255, 0.85)',
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
interface IModifiersProvidesTable {
|
interface IModifiersProvidesTable {
|
||||||
modifiers: IModifier[],
|
modifiers: IModifier[],
|
||||||
@ -156,14 +142,15 @@ export function ModifiersProvidesAddonTable(props: IModifiersProvidesTable) {
|
|||||||
let noWeaponMods = props.modifiers.filter(m => !m.reference.includes("default_weapon_modifier_hardpoint"))
|
let noWeaponMods = props.modifiers.filter(m => !m.reference.includes("default_weapon_modifier_hardpoint"))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableContainer component={StyledPaper} elevation={0}>
|
<TableContainer component={Paper}>
|
||||||
<Table size="small" aria-label="a dense table">
|
<Table size="small" aria-label="a dense table">
|
||||||
{noWeaponMods.map(m =>
|
{noWeaponMods.map(m =>
|
||||||
<TableRow
|
<TableRow
|
||||||
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
>
|
>
|
||||||
<TableCell component="th" scope="row" sx={{color: 'rgba(255,255,255,0.85)'}}>{getModName(m.reference)}</TableCell>
|
<TableCell component="th" scope="row">{getModName(m.reference)}</TableCell>
|
||||||
<TableCell component="th" scope="row" sx={{color: 'rgba(255,255,255,0.85)'}}>{getModIcon(m.reference)} {getChangeDescription(m.usageType, m.value)}</TableCell>
|
<TableCell component="th"
|
||||||
|
scope="row">{getModIcon(m.reference)} {getChangeDescription(m.usageType, m.value)}</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
)}
|
)}
|
||||||
</Table>
|
</Table>
|
||||||
@ -181,37 +168,37 @@ export function ModifiersProvidesTable(props: IModifiersProvidesResearchTable) {
|
|||||||
var affectedUnit = props.affectedData.affectedUnits.find(au => au.filename.replaceAll('.rgd', '').split(";")[0] === target || au.filename.replaceAll('.rgd', '').split(";")[1] === target);
|
var affectedUnit = props.affectedData.affectedUnits.find(au => au.filename.replaceAll('.rgd', '').split(";")[0] === target || au.filename.replaceAll('.rgd', '').split(";")[1] === target);
|
||||||
if (affectedUnit != null) {
|
if (affectedUnit != null) {
|
||||||
return <span><img style={{verticalAlign: "top", height: 25}}
|
return <span><img style={{verticalAlign: "top", height: 25}}
|
||||||
src={getIcon(affectedUnit.icon)}/><StyledLink
|
src={getIcon(affectedUnit.icon)}/><a
|
||||||
href={`/mod/${props.modId}/race/${props.race.id}/unit/${affectedUnit.id}`}>
|
href={`/mod/${props.modId}/race/${props.race.id}/unit/${affectedUnit.id}`}>
|
||||||
{affectedUnit.name}
|
{affectedUnit.name}
|
||||||
</StyledLink></span>
|
</a></span>
|
||||||
}
|
}
|
||||||
var affectedSergeant = props.affectedData.affectedSergeants.find(as => as.filename.replaceAll('.rgd', '') === target);
|
var affectedSergeant = props.affectedData.affectedSergeants.find(as => as.filename.replaceAll('.rgd', '') === target);
|
||||||
if (affectedSergeant != null) {
|
if (affectedSergeant != null) {
|
||||||
return <span><img style={{verticalAlign: "top", height: 25}}
|
return <span><img style={{verticalAlign: "top", height: 25}}
|
||||||
src={getIcon(affectedSergeant.icon)}/>{affectedSergeant.name} at <img
|
src={getIcon(affectedSergeant.icon)}/>{affectedSergeant.name} at <img
|
||||||
style={{verticalAlign: "top", height: 25}}
|
style={{verticalAlign: "top", height: 25}}
|
||||||
src={getIcon(affectedSergeant.unit.icon)}/><StyledLink
|
src={getIcon(affectedSergeant.unit.icon)}/><a
|
||||||
href={`/mod/${props.modId}/race/${props.race.id}/unit/${affectedSergeant.unit.id}`}>
|
href={`/mod/${props.modId}/race/${props.race.id}/unit/${affectedSergeant.unit.id}`}>
|
||||||
{affectedSergeant.unit.name}
|
{affectedSergeant.unit.name}
|
||||||
</StyledLink></span>
|
</a></span>
|
||||||
}
|
}
|
||||||
var affectedBuilding = props.affectedData.affectedBuildings.find(ab => ab.filename.replaceAll('.rgd', '') === target);
|
var affectedBuilding = props.affectedData.affectedBuildings.find(ab => ab.filename.replaceAll('.rgd', '') === target);
|
||||||
if (affectedBuilding != null) {
|
if (affectedBuilding != null) {
|
||||||
return <span><img style={{verticalAlign: "top", height: 25}} src={getIcon(affectedBuilding.icon)}/><StyledLink
|
return <span><img style={{verticalAlign: "top", height: 25}} src={getIcon(affectedBuilding.icon)}/><a
|
||||||
href={`/mod/${props.modId}/race/${props.race.id}/building/${affectedBuilding.id}`}>
|
href={`/mod/${props.modId}/race/${props.race.id}/building/${affectedBuilding.id}`}>
|
||||||
{affectedBuilding.name}
|
{affectedBuilding.name}
|
||||||
</StyledLink> </span>
|
</a> </span>
|
||||||
}
|
}
|
||||||
|
|
||||||
var affectedWeapon = props.affectedData.affectedWeapons.find(aw => aw.filename.replaceAll('.rgd', '') === target);
|
var affectedWeapon = props.affectedData.affectedWeapons.find(aw => aw.filename.replaceAll('.rgd', '') === target);
|
||||||
if (affectedWeapon != null) {
|
if (affectedWeapon != null) {
|
||||||
return <span>{affectedWeapon.name ? affectedWeapon.name : affectedWeapon.filename.replaceAll('_', ' ').replace('.rgd', '')} at {
|
return <span>{affectedWeapon.name ? affectedWeapon.name : affectedWeapon.filename.replaceAll('_', ' ').replace('.rgd', '')} at {
|
||||||
affectedWeapon.units.map(unit =>
|
affectedWeapon.units.map(unit =>
|
||||||
<span>{affectedWeapon != null && affectedWeapon.units.length + affectedWeapon.sergeants.length > 1 ? <br/> : <span></span>}<img style={{verticalAlign: "top", height: 25}} src={getIcon(unit.icon)}/><StyledLink
|
<span>{affectedWeapon != null && affectedWeapon.units.length + affectedWeapon.sergeants.length > 1 ? <br/> : <span></span>}<img style={{verticalAlign: "top", height: 25}} src={getIcon(unit.icon)}/><a
|
||||||
href={`/mod/${props.modId}/race/${props.race.id}/unit/${unit.id}`}>
|
href={`/mod/${props.modId}/race/${props.race.id}/unit/${unit.id}`}>
|
||||||
{unit.name}
|
{unit.name}
|
||||||
</StyledLink> </span>
|
</a> </span>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@ -219,18 +206,18 @@ export function ModifiersProvidesTable(props: IModifiersProvidesResearchTable) {
|
|||||||
<span>{affectedWeapon != null && affectedWeapon.units.length + affectedWeapon.sergeants.length > 1 ? <br/> : <span></span>}<img style={{verticalAlign: "top", height: 25}}
|
<span>{affectedWeapon != null && affectedWeapon.units.length + affectedWeapon.sergeants.length > 1 ? <br/> : <span></span>}<img style={{verticalAlign: "top", height: 25}}
|
||||||
src={getIcon(affectedSergeant.icon)}/>{affectedSergeant.name} at <img
|
src={getIcon(affectedSergeant.icon)}/>{affectedSergeant.name} at <img
|
||||||
style={{verticalAlign: "top", height: 25}}
|
style={{verticalAlign: "top", height: 25}}
|
||||||
src={getIcon(affectedSergeant.unit.icon)}/><StyledLink
|
src={getIcon(affectedSergeant.unit.icon)}/><a
|
||||||
href={`/mod/${props.modId}/race/${props.race.id}/unit/${affectedSergeant.unit.id}`}>
|
href={`/mod/${props.modId}/race/${props.race.id}/unit/${affectedSergeant.unit.id}`}>
|
||||||
{affectedSergeant.unit.name}
|
{affectedSergeant.unit.name}
|
||||||
</StyledLink> </span>
|
</a> </span>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
affectedWeapon.buildings.map(affectedBuilding =>
|
affectedWeapon.buildings.map(affectedBuilding =>
|
||||||
<span><img style={{verticalAlign: "top", height: 25}} src={getIcon(affectedBuilding.icon)}/><StyledLink
|
<span><img style={{verticalAlign: "top", height: 25}} src={getIcon(affectedBuilding.icon)}/><a
|
||||||
href={`/mod/${props.modId}/race/${props.race.id}/building/${affectedBuilding.id}`}>
|
href={`/mod/${props.modId}/race/${props.race.id}/building/${affectedBuilding.id}`}>
|
||||||
{affectedBuilding.name}
|
{affectedBuilding.name}
|
||||||
</StyledLink> </span>
|
</a> </span>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</span>
|
</span>
|
||||||
@ -241,21 +228,23 @@ export function ModifiersProvidesTable(props: IModifiersProvidesResearchTable) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableContainer component={StyledPaper} elevation={0}>
|
<TableContainer component={Paper}>
|
||||||
<Table size="small" aria-label="a dense table">
|
<Table size="small" aria-label="a dense table">
|
||||||
{mods.map(m =>
|
{mods.map(m =>
|
||||||
<TableRow
|
<TableRow
|
||||||
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
>
|
>
|
||||||
<TableCell component="th" scope="row" sx={{color: 'rgba(255,255,255,0.85)'}}>{getTarget(m.target)}</TableCell>
|
<TableCell component="th" scope="row">{getTarget(m.target)}</TableCell>
|
||||||
<TableCell component="th" scope="row" sx={{color: 'rgba(255,255,255,0.85)', minWidth: 120}}>{getModName(m.reference)}</TableCell>
|
<TableCell style={{minWidth: 120}} component="th"
|
||||||
<TableCell component="th" scope="row" sx={{color: 'rgba(255,255,255,0.85)'}}>{getModIcon(m.reference)} {getChangeDescription(m.usageType, m.value)}
|
scope="row">{getModName(m.reference)}</TableCell>
|
||||||
|
<TableCell component="th"
|
||||||
|
scope="row">{getModIcon(m.reference)} {getChangeDescription(m.usageType, m.value)}
|
||||||
{m.maxLifeTime !== undefined && m.maxLifeTime > 0 &&
|
{m.maxLifeTime !== undefined && m.maxLifeTime > 0 &&
|
||||||
<span><img style={{verticalAlign: "top"}} src='/images/Time_icon.webp'/>{m.maxLifeTime}s
|
<span><img style={{verticalAlign: "top"}} src='/images/Time_icon.webp'/>{m.maxLifeTime}s
|
||||||
</span>}
|
</span>}
|
||||||
<i style={{fontSize: 11}}>{m.exclusive ? " does not stack" : " does stack"}</i>
|
<i style={{fontSize: 11}}>{m.exclusive ? " does not stuck" : " does stuck"}</i>
|
||||||
{m.probabilityOfApplying !== undefined && m.probabilityOfApplying !== 1.0 &&
|
{m.probabilityOfApplying !== undefined && m.probabilityOfApplying !== 1.0 &&
|
||||||
<span><i style={{fontSize: 11, color: 'rgba(255,255,255,0.5)'}}> ({m.probabilityOfApplying * 100}% chance)</i>
|
<span><i style={{fontSize: 11}}> ({m.probabilityOfApplying * 100}% chance)</i>
|
||||||
</span>}
|
</span>}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import {IconUrl} from "../core/api";
|
|||||||
import {IResearchRequirements} from "../types/IResearchRequirements";
|
import {IResearchRequirements} from "../types/IResearchRequirements";
|
||||||
import {IRequirement, IRequirementLimitByBuildingDto, IRequirementSquadsDto} from "../types/IRequirement";
|
import {IRequirement, IRequirementLimitByBuildingDto, IRequirementSquadsDto} from "../types/IRequirement";
|
||||||
import {IUnitShort} from "../types/IUnitShort";
|
import {IUnitShort} from "../types/IUnitShort";
|
||||||
import {StyledLink} from "../commons/StyledLink";
|
|
||||||
|
|
||||||
interface IRequiredProps{
|
interface IRequiredProps{
|
||||||
requirement: IRequirement,
|
requirement: IRequirement,
|
||||||
@ -21,9 +20,9 @@ function Required (props: IRequiredProps) {
|
|||||||
|
|
||||||
<span> Global addon: <img style={{verticalAlign: "top", height: 25}}
|
<span> Global addon: <img style={{verticalAlign: "top", height: 25}}
|
||||||
src={getIcon(rga.icon)}/>
|
src={getIcon(rga.icon)}/>
|
||||||
<StyledLink href={`/mod/${props.modId}/race/${props.raceId}/building/${rga.buildingId}#addon-${rga.id}`}>
|
<a href={`/mod/${props.modId}/race/${props.raceId}/building/${rga.buildingId}#addon-${rga.id}`}>
|
||||||
{rga.name}
|
{rga.name}
|
||||||
</StyledLink></span>
|
</a></span>
|
||||||
)}</div>
|
)}</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,29 +30,29 @@ function Required (props: IRequiredProps) {
|
|||||||
return requirementBuildings.length > 0 && (
|
return requirementBuildings.length > 0 && (
|
||||||
<div> Buildings: <img style={{verticalAlign: "top", height: 25}}
|
<div> Buildings: <img style={{verticalAlign: "top", height: 25}}
|
||||||
src={IconUrl + requirementBuildings[0].icon.replaceAll('\\', '/')}/>
|
src={IconUrl + requirementBuildings[0].icon.replaceAll('\\', '/')}/>
|
||||||
{" "}<StyledLink href={`/mod/${props.modId}/race/${props.raceId}/building/${requirementBuildings[0].id}`}>
|
{" "}<a href={`/mod/${props.modId}/race/${props.raceId}/building/${requirementBuildings[0].id}`}>
|
||||||
{requirementBuildings[0].name}
|
{requirementBuildings[0].name}
|
||||||
</StyledLink> {requirementBuildings[1] !== undefined && <span>or <img style={{verticalAlign: "top", height: 25}}
|
</a> {requirementBuildings[1] !== undefined && <span>or <img style={{verticalAlign: "top", height: 25}}
|
||||||
src={IconUrl + requirementBuildings[1].icon.replaceAll('\\', '/')}/>
|
src={IconUrl + requirementBuildings[1].icon.replaceAll('\\', '/')}/>
|
||||||
{" "}<StyledLink href={`/mod/${props.modId}/race/${props.raceId}/building/${requirementBuildings[1].id}`}>
|
{" "}<a href={`/mod/${props.modId}/race/${props.raceId}/building/${requirementBuildings[1].id}`}>
|
||||||
{requirementBuildings[1].name}</StyledLink></span> } </div>
|
{requirementBuildings[1].name}</a></span> } </div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderRequiremenStructureExclusive(buildingExclusive: IBuildingShort) {
|
function renderRequiremenStructureExclusive(buildingExclusive: IBuildingShort) {
|
||||||
return <div> Can't be build with: <img style={{verticalAlign: "top", height: 25}}
|
return <div> Can't be build with: <img style={{verticalAlign: "top", height: 25}}
|
||||||
src={IconUrl + buildingExclusive.icon.replaceAll('\\', '/')}/>
|
src={IconUrl + buildingExclusive.icon.replaceAll('\\', '/')}/>
|
||||||
{" "}<StyledLink href={`/mod/${props.modId}/race/${props.raceId}/building/${buildingExclusive.id}`}>
|
{" "}<a href={`/mod/${props.modId}/race/${props.raceId}/building/${buildingExclusive.id}`}>
|
||||||
{buildingExclusive.name}
|
{buildingExclusive.name}
|
||||||
</StyledLink> </div>
|
</a> </div>
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderRequiremenAddonExclusive(addonShort: IBuildingAddonShort) {
|
function renderRequiremenAddonExclusive(addonShort: IBuildingAddonShort) {
|
||||||
return <div> Can't be build with: <img style={{verticalAlign: "top", height: 25}}
|
return <div> Can't be build with: <img style={{verticalAlign: "top", height: 25}}
|
||||||
src={getIcon(addonShort.icon)}/>
|
src={getIcon(addonShort.icon)}/>
|
||||||
<StyledLink href={`/mod/${props.modId}/race/${props.raceId}/building/${addonShort.buildingId}#addon-${addonShort.id}`}>
|
<a href={`/mod/${props.modId}/race/${props.raceId}/building/${addonShort.buildingId}#addon-${addonShort.id}`}>
|
||||||
{addonShort.name}
|
{addonShort.name}
|
||||||
</StyledLink></div>
|
</a></div>
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderRequirementOwnership(requirementOwnership: string[],) {
|
function renderRequirementOwnership(requirementOwnership: string[],) {
|
||||||
@ -71,8 +70,8 @@ function Required (props: IRequiredProps) {
|
|||||||
function renderLimitPerBuilding(limitPerBuilding: IRequirementLimitByBuildingDto,) {
|
function renderLimitPerBuilding(limitPerBuilding: IRequirementLimitByBuildingDto,) {
|
||||||
return <span> One <img style={{verticalAlign: "top", height: 25}}
|
return <span> One <img style={{verticalAlign: "top", height: 25}}
|
||||||
src={IconUrl + limitPerBuilding.building.icon.replaceAll('\\', '/')}/>
|
src={IconUrl + limitPerBuilding.building.icon.replaceAll('\\', '/')}/>
|
||||||
{" "}<StyledLink href={`/mod/${props.modId}/race/${props.raceId}/building/${limitPerBuilding.building.id}`}>
|
{" "}<a href={`/mod/${props.modId}/race/${props.raceId}/building/${limitPerBuilding.building.id}`}>
|
||||||
{limitPerBuilding.building.name} </StyledLink> allow produce max {limitPerBuilding.limit}</span>
|
{limitPerBuilding.building.name} </a> allow produce max {limitPerBuilding.limit}</span>
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderRequirementResearches(requirementResearches: IResearchRequirements[],) {
|
function renderRequirementResearches(requirementResearches: IResearchRequirements[],) {
|
||||||
@ -80,9 +79,9 @@ function Required (props: IRequiredProps) {
|
|||||||
|
|
||||||
<span> Research {rs.researchMustNotBeComplete ? "not" : ""}: <img style={{verticalAlign: "top", height: 25}}
|
<span> Research {rs.researchMustNotBeComplete ? "not" : ""}: <img style={{verticalAlign: "top", height: 25}}
|
||||||
src={getIcon(rs.researchShortDto.icon)}/>
|
src={getIcon(rs.researchShortDto.icon)}/>
|
||||||
<StyledLink href={`/mod/${props.modId}/race/${props.raceId}/building/${rs.researchShortDto.buildingId}#research-${rs.researchShortDto.id}`}>
|
<a href={`/mod/${props.modId}/race/${props.raceId}/building/${rs.researchShortDto.buildingId}#research-${rs.researchShortDto.id}`}>
|
||||||
{rs.researchShortDto.name}
|
{rs.researchShortDto.name}
|
||||||
</StyledLink></span>
|
</a></span>
|
||||||
)}</div>
|
)}</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,9 +90,9 @@ function Required (props: IRequiredProps) {
|
|||||||
|
|
||||||
<span> Squad: {rs.count} <img style={{verticalAlign: "top", height: 25}}
|
<span> Squad: {rs.count} <img style={{verticalAlign: "top", height: 25}}
|
||||||
src={getIcon(rs.squad.icon)}/>
|
src={getIcon(rs.squad.icon)}/>
|
||||||
<StyledLink href={`/mod/${props.modId}/race/${props.raceId}/unit/${rs.squad.id}`}>
|
<a href={`/mod/${props.modId}/race/${props.raceId}/unit/${rs.squad.id}`}>
|
||||||
{rs.squad.name}
|
{rs.squad.name}
|
||||||
</StyledLink></span>
|
</a></span>
|
||||||
)}</div>
|
)}</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,12 +101,12 @@ function Required (props: IRequiredProps) {
|
|||||||
return requirementResearches.length > 0 && (
|
return requirementResearches.length > 0 && (
|
||||||
<div> Researches: <span> <img style={{verticalAlign: "top", height: 25}}
|
<div> Researches: <span> <img style={{verticalAlign: "top", height: 25}}
|
||||||
src={getIcon(requirementResearches[0].researchShortDto.icon)}/>
|
src={getIcon(requirementResearches[0].researchShortDto.icon)}/>
|
||||||
<StyledLink href={`/mod/${props.modId}/race/${props.raceId}/building/${requirementResearches[0].researchShortDto.buildingId}#research-${requirementResearches[0].researchShortDto.id}`}>
|
<a href={`/mod/${props.modId}/race/${props.raceId}/building/${requirementResearches[0].researchShortDto.buildingId}#research-${requirementResearches[0].researchShortDto.id}`}>
|
||||||
{requirementResearches[0].researchShortDto.name}
|
{requirementResearches[0].researchShortDto.name}
|
||||||
</StyledLink></span> {requirementResearches[1] != null && <span> or <img style={{verticalAlign: "top", height: 25}} src={getIcon(requirementResearches[1].researchShortDto.icon)}/>
|
</a></span> {requirementResearches[1] != null && <span> or <img style={{verticalAlign: "top", height: 25}} src={getIcon(requirementResearches[1].researchShortDto.icon)}/>
|
||||||
<StyledLink href={`/mod/${props.modId}/race/${props.raceId}/building/${requirementResearches[1].researchShortDto.buildingId}#research-${requirementResearches[1].researchShortDto.id}`}>
|
<a href={`/mod/${props.modId}/race/${props.raceId}/building/${requirementResearches[1].researchShortDto.buildingId}#research-${requirementResearches[1].researchShortDto.id}`}>
|
||||||
{requirementResearches[1].researchShortDto.name}
|
{requirementResearches[1].researchShortDto.name}
|
||||||
</StyledLink></span>} </div>
|
</a></span>} </div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,48 +114,48 @@ function Required (props: IRequiredProps) {
|
|||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{color: 'rgba(255, 255, 255, 0.85)'}}>
|
<div>
|
||||||
<h4 style={{color: '#ffffff', fontWeight: 700}}>Required: </h4>
|
<h4>Required: </h4>
|
||||||
{requirement.requiredTotalPop !== undefined && requirement.requiredTotalPop !== null &&
|
{requirement.requiredTotalPop !== undefined && requirement.requiredTotalPop !== null &&
|
||||||
<div style={{color: 'rgba(255, 255, 255, 0.85)'}}> Population: <img style={{verticalAlign: "top", height: 25}}
|
<div> Population: <img style={{verticalAlign: "top", height: 25}}
|
||||||
src="/images/Resource_orksquadcap.gif"/>
|
src="/images/Resource_orksquadcap.gif"/>
|
||||||
{requirement.requiredTotalPop}</div>
|
{requirement.requiredTotalPop}</div>
|
||||||
}
|
}
|
||||||
{requirement.mobBonus !== null && requirement.mobBonus !== undefined &&
|
{requirement.mobBonus !== null && requirement.mobBonus !== undefined &&
|
||||||
<div style={{color: 'rgba(255, 255, 255, 0.85)'}}> Mob requirement: <img style={{verticalAlign: "top", height: 25}}
|
<div> Mob requirement: <img style={{verticalAlign: "top", height: 25}}
|
||||||
src="/images/Mob_bonus.gif"/>
|
src="/images/Mob_bonus.gif"/>
|
||||||
{requirement.mobBonus.mobvalueRequired} in radius {requirement.mobBonus.proximityRequired}</div>
|
{requirement.mobBonus.mobvalueRequired} in radius {requirement.mobBonus.proximityRequired}</div>
|
||||||
}
|
}
|
||||||
{requirement.requireAddon !== null &&
|
{requirement.requireAddon !== null &&
|
||||||
<div style={{color: 'rgba(255, 255, 255, 0.85)'}}> Addon: <img style={{verticalAlign: "top", height: 25}}
|
<div> Addon: <img style={{verticalAlign: "top", height: 25}}
|
||||||
src={IconUrl + requirement.requireAddon.icon.replaceAll('\\', '/')}/>
|
src={IconUrl + requirement.requireAddon.icon.replaceAll('\\', '/')}/>
|
||||||
<StyledLink href={`/mod/${props.modId}/race/${props.raceId}/building/${requirement.requireAddon.buildingId}#addon-${requirement.requireAddon.id}`}>
|
<a href={`/mod/${props.modId}/race/${props.raceId}/building/${requirement.requireAddon.buildingId}#addon-${requirement.requireAddon.id}`}>
|
||||||
{requirement.requireAddon.name}
|
{requirement.requireAddon.name}
|
||||||
</StyledLink>
|
</a>
|
||||||
{requirement.replaceWhenDone && <i> (old provides replace)</i>}
|
{requirement.replaceWhenDone && <i> (old provides replace)</i>}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
{requirement.requirementAddonExclusive != null &&
|
{requirement.requirementAddonExclusive != null &&
|
||||||
<div style={{color: 'rgba(255, 255, 255, 0.85)'}}>{renderRequiremenAddonExclusive(requirement.requirementAddonExclusive,)}</div>}
|
renderRequiremenAddonExclusive(requirement.requirementAddonExclusive,)}
|
||||||
{requirement.requirementBuildings.map(b =>
|
{requirement.requirementBuildings.map(b =>
|
||||||
<div key={b.id} style={{color: 'rgba(255, 255, 255, 0.85)'}}> Building: <img style={{verticalAlign: "top", height: 25}}
|
<div key={b.id}> Building: <img style={{verticalAlign: "top", height: 25}}
|
||||||
src={IconUrl + b.icon.replaceAll('\\', '/')}/>
|
src={IconUrl + b.icon.replaceAll('\\', '/')}/>
|
||||||
<StyledLink href= {'/mod/'+ props.modId +'/race/'+ props.raceId +'/building/' + b.id + "/"}>{b.name}</StyledLink></div>)
|
<a href= {'/mod/'+ props.modId +'/race/'+ props.raceId +'/building/' + b.id + "/"}>{b.name}</a></div>)
|
||||||
}
|
}
|
||||||
{requirement.requirementResearches.length !== 0 &&
|
{requirement.requirementResearches.length !== 0 &&
|
||||||
<div style={{color: 'rgba(255, 255, 255, 0.85)'}}>{renderRequirementResearches(requirement.requirementResearches,)}</div>}
|
renderRequirementResearches(requirement.requirementResearches,)}
|
||||||
{requirement.requirementSquads.length !== 0 &&
|
{requirement.requirementSquads.length !== 0 &&
|
||||||
<div style={{color: 'rgba(255, 255, 255, 0.85)'}}>{renderRequirementSquads(requirement.requirementSquads,)}</div>}
|
renderRequirementSquads(requirement.requirementSquads,)}
|
||||||
{requirement.requirementResearchesEither.length !== 0 &&
|
{requirement.requirementResearchesEither.length !== 0 &&
|
||||||
<div style={{color: 'rgba(255, 255, 255, 0.85)'}}>{renderRequirementResearchesEither(requirement.requirementResearchesEither,)}</div>}
|
renderRequirementResearchesEither(requirement.requirementResearchesEither,)}
|
||||||
{requirement.requirementBuildingsEither.length !== 0 &&
|
{requirement.requirementBuildingsEither.length !== 0 &&
|
||||||
<div style={{color: 'rgba(255, 255, 255, 0.85)'}}>{renderRequirementBuildingEither(requirement.requirementBuildingsEither,)}</div>}
|
renderRequirementBuildingEither(requirement.requirementBuildingsEither,)}
|
||||||
{requirement.requirementStructureExclusive != null &&
|
{requirement.requirementStructureExclusive != null &&
|
||||||
<div style={{color: 'rgba(255, 255, 255, 0.85)'}}>{renderRequiremenStructureExclusive(requirement.requirementStructureExclusive,)}</div>}
|
renderRequiremenStructureExclusive(requirement.requirementStructureExclusive,)}
|
||||||
{requirement.limitByBuilding !== undefined && requirement.limitByBuilding !== null && <div style={{color: 'rgba(255, 255, 255, 0.85)'}}>{renderLimitPerBuilding(requirement.limitByBuilding)}</div>}
|
{requirement.limitByBuilding !== undefined && requirement.limitByBuilding !== null && renderLimitPerBuilding(requirement.limitByBuilding)}
|
||||||
{requirement.requirementsGlobalAddons.length !== 0 &&
|
{requirement.requirementsGlobalAddons.length !== 0 &&
|
||||||
<div style={{color: 'rgba(255, 255, 255, 0.85)'}}>{renderRequirementGlobalAddons(requirement.requirementsGlobalAddons,)}</div>}
|
renderRequirementGlobalAddons(requirement.requirementsGlobalAddons,)}
|
||||||
<div style={{color: 'rgba(255, 255, 255, 0.85)'}}>{renderRequirementOwnership(requirement.requiredOwnership)}</div>
|
{renderRequirementOwnership(requirement.requiredOwnership)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import {ISergeant, IShortWeapon} from "../types/IUnit";
|
import {ISergeant, IShortWeapon} from "../types/IUnit";
|
||||||
import {Grid2, Paper, Table, TableBody, TableCell, TableContainer, TableRow, Tooltip, Typography} from "@mui/material";
|
import {Grid2, Paper, Table, TableBody, TableCell, TableContainer, TableRow, Tooltip} from "@mui/material";
|
||||||
import AvTimerOutlinedIcon from "@mui/icons-material/AvTimer";
|
import AvTimerOutlinedIcon from "@mui/icons-material/AvTimer";
|
||||||
import ArmorType from "./ArmorType";
|
import ArmorType from "./ArmorType";
|
||||||
import WeaponSlot from "./WeaponSlot";
|
import WeaponSlot from "./WeaponSlot";
|
||||||
@ -12,28 +12,6 @@ import Required from "./Required";
|
|||||||
import {ModifiersProvidesTable} from "./ModifiersProvideTable";
|
import {ModifiersProvidesTable} from "./ModifiersProvideTable";
|
||||||
import Ability from "./Ability";
|
import Ability from "./Ability";
|
||||||
import DeathExplosion from "./DeathExplosion";
|
import DeathExplosion from "./DeathExplosion";
|
||||||
import {styled} from '@mui/material/styles';
|
|
||||||
import {DescriptionBox} from "../commons/DescriptionBox";
|
|
||||||
|
|
||||||
const StyledPaper = styled(Paper)(({ theme }) => ({
|
|
||||||
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
||||||
borderRadius: '12px',
|
|
||||||
overflow: 'hidden',
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-root': {
|
|
||||||
color: 'rgba(255, 255, 255, 0.9)',
|
|
||||||
},
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-head': {
|
|
||||||
color: '#e94560',
|
|
||||||
fontWeight: 600,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const SectionTitle = styled(Typography)(({ theme }) => ({
|
|
||||||
fontWeight: 700,
|
|
||||||
mb: 2,
|
|
||||||
fontSize: '1.25rem',
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
export interface SergeantProps {
|
export interface SergeantProps {
|
||||||
@ -60,17 +38,17 @@ const Sergeant = (props: SergeantProps) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{color: 'rgba(255, 255, 255, 0.85)'}}>
|
<div>
|
||||||
<Grid2 container spacing={2}>
|
<Grid2 container spacing={2}>
|
||||||
<Grid2 size= {{xs: 12, md: 4}}>
|
<Grid2 size= {{xs: 12, md: 4}}>
|
||||||
<TableContainer component={StyledPaper} elevation={0}>
|
<TableContainer component={Paper}>
|
||||||
<Table size="small" aria-label="a dense table">
|
<Table size="small" aria-label="a dense table">
|
||||||
<TableBody id="unit-stats-table">
|
<TableBody id="unit-stats-table">
|
||||||
<TableRow
|
<TableRow
|
||||||
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
>
|
>
|
||||||
<TableCell component="th" scope="row">Cost</TableCell>
|
<TableCell component="th" scope="row">Cost</TableCell>
|
||||||
<TableCell>
|
<TableCell component="th" scope="row">
|
||||||
{sergeant.buildCostRequisition > 0 &&
|
{sergeant.buildCostRequisition > 0 &&
|
||||||
<span> <img style={{verticalAlign: "top"}}
|
<span> <img style={{verticalAlign: "top"}}
|
||||||
src="/images/Resource_requisition.gif"/>
|
src="/images/Resource_requisition.gif"/>
|
||||||
@ -115,7 +93,7 @@ const Sergeant = (props: SergeantProps) => {
|
|||||||
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
>
|
>
|
||||||
<TableCell component="th" scope="row">Armor type</TableCell>
|
<TableCell component="th" scope="row">Armor type</TableCell>
|
||||||
<TableCell>
|
<TableCell component="th" scope="row">
|
||||||
{sergeant.armorType2 == null ? <ArmorType name={sergeant.armorType.name} compact={false}/>
|
{sergeant.armorType2 == null ? <ArmorType name={sergeant.armorType.name} compact={false}/>
|
||||||
: <Tooltip title={"upgrade/debuff can turns to " + sergeant.armorType2.name}><span><ArmorType name={sergeant.armorType.name} compact={false}/></span></Tooltip> }
|
: <Tooltip title={"upgrade/debuff can turns to " + sergeant.armorType2.name}><span><ArmorType name={sergeant.armorType.name} compact={false}/></span></Tooltip> }
|
||||||
</TableCell>
|
</TableCell>
|
||||||
@ -124,7 +102,7 @@ const Sergeant = (props: SergeantProps) => {
|
|||||||
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
>
|
>
|
||||||
<TableCell component="th" scope="row">Health</TableCell>
|
<TableCell component="th" scope="row">Health</TableCell>
|
||||||
<TableCell>
|
<TableCell component="th" scope="row">
|
||||||
<span><img style={{verticalAlign: "top"}}
|
<span><img style={{verticalAlign: "top"}}
|
||||||
src="/images/Health_icon.webp"/>
|
src="/images/Health_icon.webp"/>
|
||||||
{sergeant.health} {sergeant.healthRegeneration > 0 &&
|
{sergeant.health} {sergeant.healthRegeneration > 0 &&
|
||||||
@ -135,7 +113,7 @@ const Sergeant = (props: SergeantProps) => {
|
|||||||
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
>
|
>
|
||||||
<TableCell component="th" scope="row">Morale</TableCell>
|
<TableCell component="th" scope="row">Morale</TableCell>
|
||||||
<TableCell>
|
<TableCell component="th" scope="row">
|
||||||
{sergeant.moraleIncomeMax && <span><img style={{verticalAlign: "top"}}
|
{sergeant.moraleIncomeMax && <span><img style={{verticalAlign: "top"}}
|
||||||
src="/images/ARM_Morale.webp"/> +{sergeant.moraleIncomeMax} </span>}
|
src="/images/ARM_Morale.webp"/> +{sergeant.moraleIncomeMax} </span>}
|
||||||
{sergeant.moraleRate && <span>+ {sergeant.moraleRate}/s</span> }
|
{sergeant.moraleRate && <span>+ {sergeant.moraleRate}/s</span> }
|
||||||
@ -147,19 +125,21 @@ const Sergeant = (props: SergeantProps) => {
|
|||||||
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
>
|
>
|
||||||
<TableCell component="th" scope="row">Mass</TableCell>
|
<TableCell component="th" scope="row">Mass</TableCell>
|
||||||
<TableCell>{sergeant.mass}</TableCell>
|
<TableCell component="th" scope="row">
|
||||||
|
{sergeant.mass}
|
||||||
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow
|
<TableRow
|
||||||
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
>
|
>
|
||||||
<TableCell component="th" scope="row">Vision</TableCell>
|
<TableCell component="th" scope="row">Vision</TableCell>
|
||||||
<TableCell>
|
<TableCell component="th" scope="row">
|
||||||
<Vision sight={sergeant.sightRadius} detect={sergeant.detectRadius}/>
|
<Vision sight={sergeant.sightRadius} detect={sergeant.detectRadius}/>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
{sergeant.mobValue != null &&
|
{sergeant.mobValue != null &&
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell component="th" scope="row" >Mob value</TableCell>
|
<TableCell>Mob value</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<span> <img style={{height: 20, verticalAlign: "top"}} src="/images/Mob_bonus.gif"/> {sergeant.mobValue} </span>
|
<span> <img style={{height: 20, verticalAlign: "top"}} src="/images/Mob_bonus.gif"/> {sergeant.mobValue} </span>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
@ -170,20 +150,20 @@ const Sergeant = (props: SergeantProps) => {
|
|||||||
</TableContainer>
|
</TableContainer>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
<Grid2 size={8}>
|
<Grid2 size={8}>
|
||||||
<DescriptionBox>
|
<div style={{whiteSpace: "pre-wrap"}}>
|
||||||
{sergeant.description}
|
{sergeant.description}
|
||||||
</DescriptionBox>
|
</div>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
{sergeant.requirements !== null &&
|
{sergeant.requirements !== null &&
|
||||||
<Grid2 size={{xs: 12, md: 12}}>
|
<Grid2 size={{xs: 12, md: 12}}>
|
||||||
<Required requirement={sergeant.requirements} modId={props.mod.id} raceId={props.race.id}/>
|
<Required requirement={sergeant.requirements} modId={props.mod.id} raceId={props.race.id}/>
|
||||||
</Grid2>}
|
</Grid2>}
|
||||||
{sergeant.modifiers.length > 0 && <Grid2 size={12}>
|
{sergeant.modifiers.length > 0 && <Grid2 size={12}>
|
||||||
<SectionTitle>Affected on</SectionTitle>
|
<h3>Affected on</h3>
|
||||||
<ModifiersProvidesTable modifiers={sergeant.modifiers} modId={props.mod.id} race={props.race} affectedData={null}/>
|
<ModifiersProvidesTable modifiers={sergeant.modifiers} modId={props.mod.id} race={props.race} affectedData={null}/>
|
||||||
</Grid2>}
|
</Grid2>}
|
||||||
{sergeant.abilities.length > 0 && <Grid2 size={12}>
|
{sergeant.abilities.length > 0 && <Grid2 size={12}>
|
||||||
<SectionTitle>Abilities</SectionTitle>
|
<h3>Abilities</h3>
|
||||||
{sergeant.abilities.map(a =>
|
{sergeant.abilities.map(a =>
|
||||||
<Ability mod={props.mod} ability={a} race={props.race}/>
|
<Ability mod={props.mod} ability={a} race={props.race}/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -1,45 +1,10 @@
|
|||||||
import React, {useEffect, useState} from "react";
|
import React, {useEffect, useState} from "react";
|
||||||
import {AvailableBuildings, AvailableUnits} from "../core/api";
|
import {AvailableBuildings, AvailableUnits} from "../core/api";
|
||||||
import {Grid2, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper} from "@mui/material";
|
import {Grid2, Link, Table, TableBody, TableCell, TableContainer, TableHead, TableRow} from "@mui/material";
|
||||||
import {styled} from '@mui/material/styles';
|
|
||||||
import {IRaceUnits, IUnitShort} from "../types/IUnitShort";
|
import {IRaceUnits, IUnitShort} from "../types/IUnitShort";
|
||||||
import {IBuildingShort, IRaceBuildings} from "../types/IBuildingShort";
|
import {IBuildingShort, IRaceBuildings} from "../types/IBuildingShort";
|
||||||
import {StyledLink} from "../commons/StyledLink";
|
|
||||||
|
|
||||||
|
|
||||||
// Styled components for dark theme
|
|
||||||
const StyledPaper = styled(Paper)(({ theme }) => ({
|
|
||||||
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
||||||
borderRadius: '12px',
|
|
||||||
overflow: 'hidden',
|
|
||||||
}));
|
|
||||||
|
|
||||||
const StyledTable = styled(Table)(({ theme }) => ({
|
|
||||||
'& .MuiTableCell-head': {
|
|
||||||
backgroundColor: 'rgba(233, 69, 96, 0.15)',
|
|
||||||
fontWeight: 700,
|
|
||||||
fontSize: '1rem',
|
|
||||||
borderBottom: '2px solid rgba(233, 69, 96, 0.3)',
|
|
||||||
},
|
|
||||||
'& .MuiTableCell-body': {
|
|
||||||
color: 'rgba(255, 255, 255, 0.85)',
|
|
||||||
borderBottom: '1px solid rgba(255, 255, 255, 0.05)',
|
|
||||||
fontSize: '0.9rem',
|
|
||||||
},
|
|
||||||
'& .MuiTableRow-hover:hover': {
|
|
||||||
backgroundColor: 'rgba(233, 69, 96, 0.08)',
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const StyledHeaderLink = styled(StyledLink)(({ theme }) => ({
|
|
||||||
fontWeight: 700,
|
|
||||||
fontSize: '1.1rem',
|
|
||||||
'&:hover': {
|
|
||||||
color: '#e94560',
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
interface IUnitsTable {
|
interface IUnitsTable {
|
||||||
racesUnits: IRaceUnits[]
|
racesUnits: IRaceUnits[]
|
||||||
racesBuildings: IRaceBuildings[]
|
racesBuildings: IRaceBuildings[]
|
||||||
@ -47,7 +12,6 @@ interface IUnitsTable {
|
|||||||
|
|
||||||
export default function UnitsTable(prop: {modId: number}) {
|
export default function UnitsTable(prop: {modId: number}) {
|
||||||
|
|
||||||
|
|
||||||
const [unitsTable, setUnitsTable] = useState<IUnitsTable>({
|
const [unitsTable, setUnitsTable] = useState<IUnitsTable>({
|
||||||
racesUnits: [],
|
racesUnits: [],
|
||||||
racesBuildings: []
|
racesBuildings: []
|
||||||
@ -55,19 +19,15 @@ export default function UnitsTable(prop: {modId: number}) {
|
|||||||
|
|
||||||
|
|
||||||
function getUnitRef(modId: number, raceId: string, unit: IUnitShort) {
|
function getUnitRef(modId: number, raceId: string, unit: IUnitShort) {
|
||||||
return <span style={{fontSize: 11}}>
|
return <span style={{fontSize: 11}}><Link href={"/mod/" + modId + "/race/" + raceId + "/unit/" + unit.id}>
|
||||||
<StyledLink href={"/mod/" + modId + "/race/" + raceId + "/unit/" + unit.id}>
|
|
||||||
{unit.name}
|
{unit.name}
|
||||||
</StyledLink><br/>
|
</Link><br/></span>
|
||||||
</span>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBuildingRef(modId: number, raceId: string, building: IBuildingShort) {
|
function getBuildingRef(modId: number, raceId: string, building: IBuildingShort) {
|
||||||
return <span style={{fontSize: 11}}>
|
return <span style={{fontSize: 11}}><Link href={"/mod/" + modId + "/race/" + raceId + "/building/" + building.id}>
|
||||||
<StyledLink href={"/mod/" + modId + "/race/" + raceId + "/building/" + building.id}>
|
|
||||||
{building.name}
|
{building.name}
|
||||||
</StyledLink><br/>
|
<br/></Link></span>
|
||||||
</span>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -139,31 +99,31 @@ export default function UnitsTable(prop: {modId: number}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function generateRaceUnitTable(racesUnitsPart: IRaceUnits[], racesBuildings: IRaceBuildings[]){
|
function generateRaceUnitTable(racesUnitsPart: IRaceUnits[], racesBuildings: IRaceBuildings[]){
|
||||||
return (<StyledPaper elevation={0}>
|
return (<TableContainer>
|
||||||
{<StyledTable sx={{minWidth: 650}} size="small" aria-label="a dense table">
|
{<Table sx={{minWidth: 650}} size="small" aria-label="a dense table">
|
||||||
<TableHead>
|
<TableHead>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
{racesUnitsPart.map(raceUnits => <TableCell><h2><StyledHeaderLink
|
{racesUnitsPart.map(raceUnits => <TableCell><h2><Link color="inherit"
|
||||||
href={"/mod/" + prop.modId + "/race/" + raceUnits.race.id}>{raceUnits.race.name}</StyledHeaderLink>
|
href={"/mod/" + prop.modId + "/race/" + raceUnits.race.id}>{raceUnits.race.name}</Link>
|
||||||
</h2></TableCell>)}
|
</h2></TableCell>)}
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
<TableRow>
|
<TableRow style={{verticalAlign: 'top'}}>
|
||||||
{racesUnitsPart.map(raceUnits =>
|
{racesUnitsPart.map(raceUnits =>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
{getUnitsRef(raceUnits.infantry.concat(raceUnits.support), raceUnits.race.id)}
|
{getUnitsRef(raceUnits.infantry.concat(raceUnits.support), raceUnits.race.id)}
|
||||||
</TableCell>)
|
</TableCell>)
|
||||||
}
|
}
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow style={{verticalAlign: 'top'}}>
|
||||||
{racesUnitsPart.map(raceUnits =>
|
{racesUnitsPart.map(raceUnits =>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
{getUnitsRef(raceUnits.tech, raceUnits.race.id)}
|
{getUnitsRef(raceUnits.tech, raceUnits.race.id)}
|
||||||
</TableCell>)
|
</TableCell>)
|
||||||
}
|
}
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow style={{verticalAlign: 'top'}}>
|
||||||
{racesBuildings.map(raceBuilding =>
|
{racesBuildings.map(raceBuilding =>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
{raceBuilding.buildings.map(building => getBuildingRef(prop.modId, raceBuilding.race.id, building))}
|
{raceBuilding.buildings.map(building => getBuildingRef(prop.modId, raceBuilding.race.id, building))}
|
||||||
@ -171,8 +131,8 @@ export default function UnitsTable(prop: {modId: number}) {
|
|||||||
}
|
}
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</StyledTable>}
|
</Table>}
|
||||||
</StyledPaper>)
|
</TableContainer>)
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateRaceUnitTables(racesUnits: IRaceUnits[], racesBuildings: IRaceBuildings[], raceCount: number){
|
function generateRaceUnitTables(racesUnits: IRaceUnits[], racesBuildings: IRaceBuildings[], raceCount: number){
|
||||||
@ -196,8 +156,8 @@ export default function UnitsTable(prop: {modId: number}) {
|
|||||||
function generateRaceList(unitsTable: IUnitsTable){
|
function generateRaceList(unitsTable: IUnitsTable){
|
||||||
return unitsTable.racesUnits.sort(function (a, b) {
|
return unitsTable.racesUnits.sort(function (a, b) {
|
||||||
return a.race.name.localeCompare(b.race.name);
|
return a.race.name.localeCompare(b.race.name);
|
||||||
}).map(raceUnits => <h5 key={raceUnits.race.id}><StyledLink
|
}).map(raceUnits => <h5 key={raceUnits.race.id}><Link color="inherit"
|
||||||
href={"/mod/" + prop.modId + "/race/" + raceUnits.race.id}>{raceUnits.race.name}</StyledLink><br/>
|
href={"/mod/" + prop.modId + "/race/" + raceUnits.race.id}>{raceUnits.race.name}</Link><br/>
|
||||||
</h5>)
|
</h5>)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,15 +6,6 @@ import {ExpandMore} from "@mui/icons-material";
|
|||||||
import {IMod} from "../types/Imod";
|
import {IMod} from "../types/Imod";
|
||||||
import {Irace} from "../types/Irace";
|
import {Irace} from "../types/Irace";
|
||||||
import WeaponFull from "./WeaponFull";
|
import WeaponFull from "./WeaponFull";
|
||||||
import {styled} from '@mui/material/styles';
|
|
||||||
|
|
||||||
const StyledAccordion = styled(Accordion)(({ theme }) => ({
|
|
||||||
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
||||||
borderRadius: '12px',
|
|
||||||
'&:before': { display: 'none' },
|
|
||||||
'&.Mui-expanded': { margin: '0 0 8px 0' },
|
|
||||||
}));
|
|
||||||
|
|
||||||
interface IWeaponProps {
|
interface IWeaponProps {
|
||||||
weapon: IShortWeapon,
|
weapon: IShortWeapon,
|
||||||
@ -43,26 +34,23 @@ class Weapon extends React.Component<IWeaponProps, any> {
|
|||||||
const weapon = this.props.weapon
|
const weapon = this.props.weapon
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{marginBottom: 10}}><StyledAccordion TransitionProps={{ unmountOnExit: true, timeout: 100 }}>
|
<div style={{marginBottom: 10}}><Accordion TransitionProps={{ unmountOnExit: true, timeout: 100 }}>
|
||||||
<AccordionSummary
|
<AccordionSummary
|
||||||
expandIcon={<ExpandMore sx={{color: '#ffffff'}}/>}
|
expandIcon={<ExpandMore/>}
|
||||||
aria-controls="panel1-content"
|
aria-controls="panel1-content"
|
||||||
id="panel1-header"
|
id="panel1-header"
|
||||||
sx={{color: '#ffffff'}}
|
|
||||||
>
|
>
|
||||||
<span style={{fontSize: 18, color: '#ffffff'}}> {!this.props.isDefault && weapon.icon && !weapon.icon.endsWith("upgrade.png") ?
|
<span style={{fontSize: 18}}> {!this.props.isDefault && weapon.icon && !weapon.icon.endsWith("upgrade.png") ?
|
||||||
<img className="weaponIcon" src={IconUrl + weapon.icon.replaceAll('\\', '/')}/> : (
|
<img className="weaponIcon" src={IconUrl + weapon.icon.replaceAll('\\', '/')}/> : (
|
||||||
weapon.isMeleeWeapon ?
|
weapon.isMeleeWeapon ?
|
||||||
<img className="weaponIcon" src="/images/MeleeStance_icon_bw.jpg"/> :
|
<img className="weaponIcon" src="/images/MeleeStance_icon_bw.jpg"/> :
|
||||||
<img className="weaponIcon" src="/images/RangedStance_icon_bw.jpg"/>
|
<img className="weaponIcon" src="/images/RangedStance_icon_bw.jpg"/>
|
||||||
)} {weapon.name ? weapon.name : this.humanReadableName(weapon.filename)}
|
)} {weapon.name ? weapon.name : this.humanReadableName(weapon.filename)} </span>
|
||||||
{this.props.isDefault && <i style={{fontSize: 12, color: 'rgba(255,255,255,0.5)'}}> (default)</i>}
|
|
||||||
</span>
|
|
||||||
</AccordionSummary>
|
</AccordionSummary>
|
||||||
<AccordionDetails sx={{color: 'rgba(255,255,255,0.85)'}}>
|
<AccordionDetails>
|
||||||
<WeaponFull weaponId={weapon.id} isDefault={this.props.isDefault} mod={this.props.mod} race={this.props.race} haveReinforceMenu={this.props.haveReinforceMenu}/>
|
<WeaponFull weaponId={weapon.id} isDefault={this.props.isDefault} mod={this.props.mod} race={this.props.race} haveReinforceMenu={this.props.haveReinforceMenu}/>
|
||||||
</AccordionDetails>
|
</AccordionDetails>
|
||||||
</StyledAccordion></div>
|
</Accordion></div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,8 +22,6 @@ import {Irace} from "../types/Irace";
|
|||||||
import {IRaceUnits} from "../types/IUnitShort";
|
import {IRaceUnits} from "../types/IUnitShort";
|
||||||
import {IRaceBuildings} from "../types/IBuildingShort";
|
import {IRaceBuildings} from "../types/IBuildingShort";
|
||||||
import {ModifiersProvidesTable} from "./ModifiersProvideTable";
|
import {ModifiersProvidesTable} from "./ModifiersProvideTable";
|
||||||
import {DescriptionBox} from "../commons/DescriptionBox";
|
|
||||||
import AvTimerOutlinedIcon from "@mui/icons-material/AvTimer";
|
|
||||||
|
|
||||||
interface IWeaponFull {
|
interface IWeaponFull {
|
||||||
currentTable: string;
|
currentTable: string;
|
||||||
@ -39,32 +37,16 @@ export default function WeaponFull(props: {weaponId: number, isDefault: Boolean,
|
|||||||
|
|
||||||
const StyledTableCell = styled(TableCell)(({theme}) => ({
|
const StyledTableCell = styled(TableCell)(({theme}) => ({
|
||||||
[`&.${tableCellClasses.head}`]: {
|
[`&.${tableCellClasses.head}`]: {
|
||||||
backgroundColor: 'rgba(233, 69, 96, 0.15)',
|
backgroundColor: "rgb(244,244,244)",
|
||||||
marginRight: 'auto',
|
marginRight: 'auto',
|
||||||
marginLeft: 'auto',
|
marginLeft: 'auto',
|
||||||
paddingLeft: 10,
|
paddingLeft: 10
|
||||||
borderBottom: '2px solid rgba(233, 69, 96, 0.3)',
|
|
||||||
},
|
},
|
||||||
[`&.${tableCellClasses.body}`]: {
|
[`&.${tableCellClasses.body}`]: {
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
color: 'rgba(255, 255, 255, 0.85)',
|
|
||||||
paddingRight: 18,
|
paddingRight: 18,
|
||||||
paddingLeft: 10,
|
paddingLeft: 10
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const StyledPaper = styled(Paper)(({ theme }) => ({
|
|
||||||
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
||||||
borderRadius: '12px',
|
|
||||||
overflow: 'hidden',
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-root': {
|
|
||||||
color: 'rgba(255, 255, 255, 0.9)',
|
|
||||||
},
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-head': {
|
|
||||||
color: '#e94560',
|
|
||||||
fontWeight: 600,
|
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -151,68 +133,84 @@ export default function WeaponFull(props: {weaponId: number, isDefault: Boolean,
|
|||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{color: 'rgba(255, 255, 255, 0.85)'}}>
|
<div>
|
||||||
<Grid2 container spacing={2}>
|
<Grid2 container spacing={2}>
|
||||||
{!props.isDefault && <Grid2 size={12}>
|
<Grid2 size={12}>
|
||||||
<DescriptionBox>
|
<div style={{whiteSpace: "pre-wrap"}}>
|
||||||
<span className="weaponDescription">{weapon.description}</span>
|
<span
|
||||||
</DescriptionBox>
|
className="weaponDescription">{props.isDefault ? "Default weapon" : weapon.description}</span>
|
||||||
</Grid2>}
|
</div>
|
||||||
|
</Grid2>
|
||||||
|
|
||||||
<Grid2 size={{xs: 12, md: 4}}>
|
<Grid2 size={{xs: 12, md: 4}}>
|
||||||
<TableContainer component={StyledPaper} elevation={0}>
|
<TableContainer component={Paper}>
|
||||||
<Table size="small" aria-label="a dense table">
|
<Table size="small" aria-label="a dense table">
|
||||||
|
{/*<TableHead><TableRow><TableCell component="th" scope="row"><b>Damage</b></TableCell><TableCell/></TableRow></TableHead>*/}
|
||||||
<TableBody>
|
<TableBody>
|
||||||
<TableRow
|
<TableRow
|
||||||
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
>
|
>
|
||||||
<TableCell component="th" scope="row">Base damage</TableCell>
|
<TableCell component="th" scope="row">Base damage</TableCell>
|
||||||
<TableCell>{weapon.minDamage} {weapon.maxDamage !== weapon.minDamage && "- " + weapon.maxDamage}</TableCell>
|
<TableCell component="th"
|
||||||
|
scope="row">{weapon.minDamage} {weapon.maxDamage !== weapon.minDamage && "- " + weapon.maxDamage}
|
||||||
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow
|
<TableRow
|
||||||
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
>
|
>
|
||||||
<TableCell component="th" scope="row">Accuracy</TableCell>
|
<TableCell component="th" scope="row">Accuracy</TableCell>
|
||||||
<TableCell>{weapon.accuracy.toFixed(3).replace(/[,.]?0+$/, '')}</TableCell>
|
<TableCell component="th"
|
||||||
|
scope="row">{weapon.accuracy.toFixed(3).replace(/[,.]?0+$/, '')}
|
||||||
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow
|
<TableRow
|
||||||
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
>
|
>
|
||||||
<TableCell component="th" scope="row">Accuracy moving</TableCell>
|
<TableCell component="th" scope="row">Accuracy moving</TableCell>
|
||||||
<TableCell>{weapon.setupTime === 0 && weapon.accuracy - weapon.accuracyReductionMoving > 0 ? (weapon.accuracy - weapon.accuracyReductionMoving).toFixed(3).replace(/[,.]?0+$/, '') : "-"}</TableCell>
|
<TableCell component="th"
|
||||||
|
scope="row">{weapon.setupTime === 0 && weapon.accuracy - weapon.accuracyReductionMoving > 0 ? (weapon.accuracy - weapon.accuracyReductionMoving).toFixed(3).replace(/[,.]?0+$/, '') : "-"}
|
||||||
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</TableContainer>
|
</TableContainer>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
<Grid2 size={{xs: 12, md: 4}}>
|
<Grid2 size={{xs: 12, md: 4}}>
|
||||||
<TableContainer component={StyledPaper} elevation={0}>
|
<TableContainer component={Paper}>
|
||||||
<Table size="small" aria-label="a dense table">
|
<Table size="small" aria-label="a dense table">
|
||||||
<TableBody>
|
<TableBody>
|
||||||
<TableRow
|
<TableRow
|
||||||
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
>
|
>
|
||||||
<TableCell component="th" scope="row">Reload time</TableCell>
|
<TableCell component="th" scope="row">Reload time</TableCell>
|
||||||
<TableCell>{weapon.reloadTime}</TableCell>
|
<TableCell component="th"
|
||||||
|
scope="row">{weapon.reloadTime}
|
||||||
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow
|
<TableRow
|
||||||
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
>
|
>
|
||||||
<TableCell component="th" scope="row">Range</TableCell>
|
<TableCell component="th" scope="row">Range</TableCell>
|
||||||
<TableCell>{weapon.maxRange ? (weapon.maxRange) : "-"} {weapon.minRange ? "(min " + (weapon.minRange) + ")" : ""}</TableCell>
|
<TableCell component="th"
|
||||||
|
scope="row">{weapon.maxRange ? (weapon.maxRange) : "-"} {weapon.minRange ? "(min " + (weapon.minRange) + ")" : ""}
|
||||||
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow
|
<TableRow
|
||||||
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
>
|
>
|
||||||
<TableCell component="th" scope="row">Damage radius</TableCell>
|
<TableCell component="th" scope="row">Damage radius</TableCell>
|
||||||
<TableCell>{weapon.damageRadius ? (weapon.damageRadius) : "-"}</TableCell>
|
<TableCell component="th"
|
||||||
|
scope="row">{weapon.damageRadius ? (weapon.damageRadius) : "-"}
|
||||||
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</TableContainer>
|
</TableContainer>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
<Grid2 size={{xs: 12, md: 4}}>
|
<Grid2 size={{xs: 12, md: 4}}>
|
||||||
<TableContainer component={StyledPaper} elevation={0}>
|
<TableContainer component={Paper}>
|
||||||
<Table size="small" aria-label="a dense table">
|
<Table size="small" aria-label="a dense table">
|
||||||
<TableBody>
|
<TableBody>
|
||||||
<TableRow
|
<TableRow
|
||||||
@ -220,7 +218,8 @@ export default function WeaponFull(props: {weaponId: number, isDefault: Boolean,
|
|||||||
>
|
>
|
||||||
<TableCell component="th" scope="row">Cost</TableCell>
|
<TableCell component="th" scope="row">Cost</TableCell>
|
||||||
{(weapon.costRequisition > 0 || weapon.costPower > 0) ?
|
{(weapon.costRequisition > 0 || weapon.costPower > 0) ?
|
||||||
<TableCell>
|
<TableCell component="th"
|
||||||
|
scope="row">
|
||||||
{weapon.costRequisition > 0 &&
|
{weapon.costRequisition > 0 &&
|
||||||
<span> <img style={{verticalAlign: "top"}}
|
<span> <img style={{verticalAlign: "top"}}
|
||||||
src="/images/Resource_requisition.gif"/>
|
src="/images/Resource_requisition.gif"/>
|
||||||
@ -229,24 +228,24 @@ export default function WeaponFull(props: {weaponId: number, isDefault: Boolean,
|
|||||||
<span> <img style={{verticalAlign: "top"}}
|
<span> <img style={{verticalAlign: "top"}}
|
||||||
src="/images/Resource_power.gif"/>
|
src="/images/Resource_power.gif"/>
|
||||||
{weapon.costPower.toFixed(0)}</span>}
|
{weapon.costPower.toFixed(0)}</span>}
|
||||||
{(weapon.costTimeSeconds !== undefined && weapon.costTimeSeconds > 0) &&
|
</TableCell> : <TableCell component="th" scope="row"> - </TableCell>
|
||||||
<span> <AvTimerOutlinedIcon
|
|
||||||
style={{verticalAlign: "top", fontSize: "18px"}}/>
|
|
||||||
{weapon.costTimeSeconds}s</span>}
|
|
||||||
</TableCell> : <TableCell> - </TableCell>
|
|
||||||
}
|
}
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow
|
<TableRow
|
||||||
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
>
|
>
|
||||||
<TableCell component="th" scope="row">Setup time</TableCell>
|
<TableCell component="th" scope="row">Setup time</TableCell>
|
||||||
<TableCell>{weapon.setupTime != 0 ? (weapon.setupTime).toFixed(3).replace(/[,.]?0+$/, '') : "-"}</TableCell>
|
<TableCell component="th"
|
||||||
|
scope="row">{weapon.setupTime != 0 ? (weapon.setupTime).toFixed(3).replace(/[,.]?0+$/, '') : "-"}
|
||||||
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow
|
<TableRow
|
||||||
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
>
|
>
|
||||||
<TableCell component="th" scope="row">Throw force</TableCell>
|
<TableCell component="th" scope="row">Throw force</TableCell>
|
||||||
<TableCell>{weapon.throwForceMin != 0 ? weapon.throwForceMin + " - " + weapon.throwForceMax : "-"}</TableCell>
|
<TableCell component="th"
|
||||||
|
scope="row">{weapon.throwForceMin != 0 ? weapon.throwForceMin + " - " + weapon.throwForceMax : "-"}
|
||||||
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
@ -260,10 +259,9 @@ export default function WeaponFull(props: {weaponId: number, isDefault: Boolean,
|
|||||||
aria-label="Platform"
|
aria-label="Platform"
|
||||||
value={weaoponFull.currentTable}
|
value={weaoponFull.currentTable}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
sx={{ mb: 2 }}
|
|
||||||
>
|
>
|
||||||
<ToggleButton size="small" value="dps" sx={{ color: '#ffffff', '&.Mui-selected': { borderColor: '#e94560', color: '#e94560', backgroundColor: 'rgba(233, 69, 96, 0.15)' } }}>Dps</ToggleButton>
|
<ToggleButton size="small" value="dps">Dps</ToggleButton>
|
||||||
<ToggleButton size="small" value="one hit" sx={{ color: '#ffffff', '&.Mui-selected': {borderColor: '#e94560', color: '#e94560', backgroundColor: 'rgba(233, 69, 96, 0.15)' } }}>One hit average damage</ToggleButton>
|
<ToggleButton size="small" value="one hit">One hit average damage</ToggleButton>
|
||||||
</ToggleButtonGroup>
|
</ToggleButtonGroup>
|
||||||
<TableContainer>
|
<TableContainer>
|
||||||
{ props.mod !== undefined && props.mod.technicalName === 'UltimateApocalypse' ?
|
{ props.mod !== undefined && props.mod.technicalName === 'UltimateApocalypse' ?
|
||||||
@ -292,7 +290,7 @@ export default function WeaponFull(props: {weaponId: number, isDefault: Boolean,
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
<TableRow>
|
||||||
<StyledTableCell>{getTotalDamage(infLowPiercing)}</StyledTableCell>
|
<StyledTableCell>{getTotalDamage(infLowPiercing)}</StyledTableCell>
|
||||||
<StyledTableCell>{getTotalDamage(infMedPiercing)}</StyledTableCell>
|
<StyledTableCell>{getTotalDamage(infMedPiercing)}</StyledTableCell>
|
||||||
<StyledTableCell>{getTotalDamage(infHighPiercing)}</StyledTableCell>
|
<StyledTableCell>{getTotalDamage(infHighPiercing)}</StyledTableCell>
|
||||||
@ -327,13 +325,13 @@ export default function WeaponFull(props: {weaponId: number, isDefault: Boolean,
|
|||||||
name={ArmorTypeNames.BuildingSuper}/></StyledTableCell>
|
name={ArmorTypeNames.BuildingSuper}/></StyledTableCell>
|
||||||
<StyledTableCell><img style={{verticalAlign: "top"}}
|
<StyledTableCell><img style={{verticalAlign: "top"}}
|
||||||
src="/images/ARM_Morale.webp"/>
|
src="/images/ARM_Morale.webp"/>
|
||||||
<div style={{width: 20, fontSize: 12, height: 50, color: 'rgba(255,255,255,0.7)'}}>
|
<div style={{width: 20, fontSize: 12, height: 50}}>
|
||||||
<i>Morale</i></div>
|
<i>Morale</i></div>
|
||||||
</StyledTableCell>
|
</StyledTableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
<TableRow>
|
||||||
<StyledTableCell>{getTotalDamage(vehLowPiercing)}</StyledTableCell>
|
<StyledTableCell>{getTotalDamage(vehLowPiercing)}</StyledTableCell>
|
||||||
<StyledTableCell>{getTotalDamage(vehMedPiercing)}</StyledTableCell>
|
<StyledTableCell>{getTotalDamage(vehMedPiercing)}</StyledTableCell>
|
||||||
<StyledTableCell>{getTotalDamage(vehHighPiercing)}</StyledTableCell>
|
<StyledTableCell>{getTotalDamage(vehHighPiercing)}</StyledTableCell>
|
||||||
@ -381,13 +379,13 @@ export default function WeaponFull(props: {weaponId: number, isDefault: Boolean,
|
|||||||
name={ArmorTypeNames.BuildingHigh}/></StyledTableCell>
|
name={ArmorTypeNames.BuildingHigh}/></StyledTableCell>
|
||||||
<StyledTableCell><img style={{verticalAlign: "top"}}
|
<StyledTableCell><img style={{verticalAlign: "top"}}
|
||||||
src="/images/ARM_Morale.webp"/>
|
src="/images/ARM_Morale.webp"/>
|
||||||
<div style={{width: 20, fontSize: 12, height: 50, color: 'rgba(255,255,255,0.7)'}}>
|
<div style={{width: 20, fontSize: 12, height: 50}}>
|
||||||
<i>Morale</i></div>
|
<i>Morale</i></div>
|
||||||
</StyledTableCell>
|
</StyledTableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
<TableRow>
|
||||||
<StyledTableCell>{getTotalDamage(infLowPiercing)}</StyledTableCell>
|
<StyledTableCell>{getTotalDamage(infLowPiercing)}</StyledTableCell>
|
||||||
<StyledTableCell>{getTotalDamage(infMedPiercing)}</StyledTableCell>
|
<StyledTableCell>{getTotalDamage(infMedPiercing)}</StyledTableCell>
|
||||||
<StyledTableCell>{getTotalDamage(infHighPiercing)}</StyledTableCell>
|
<StyledTableCell>{getTotalDamage(infHighPiercing)}</StyledTableCell>
|
||||||
@ -413,7 +411,7 @@ export default function WeaponFull(props: {weaponId: number, isDefault: Boolean,
|
|||||||
|
|
||||||
</Grid2>
|
</Grid2>
|
||||||
{weapon.modifiers.length > 0 && <Grid2 size={12}>
|
{weapon.modifiers.length > 0 && <Grid2 size={12}>
|
||||||
<h3 style={{color: '#ffffff', fontWeight: 700}}>Modifiers</h3>
|
<h3>Modifiers</h3>
|
||||||
<ModifiersProvidesTable modifiers={weapon.modifiers} modId={props.mod.id} race={props.race} affectedData={null}/>
|
<ModifiersProvidesTable modifiers={weapon.modifiers} modId={props.mod.id} race={props.race} affectedData={null}/>
|
||||||
</Grid2>}
|
</Grid2>}
|
||||||
{weapon.requirements !== null && !props.isDefault && props.haveReinforceMenu &&
|
{weapon.requirements !== null && !props.isDefault && props.haveReinforceMenu &&
|
||||||
@ -427,7 +425,7 @@ export default function WeaponFull(props: {weaponId: number, isDefault: Boolean,
|
|||||||
{!props.isDefault && props.haveReinforceMenu && <b className="hotkey">Hotkey: {weapon.hotkey}</b>}
|
{!props.isDefault && props.haveReinforceMenu && <b className="hotkey">Hotkey: {weapon.hotkey}</b>}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
} else return <div style={{color: 'rgba(255, 255, 255, 0.5)'}}>loading...</div>;
|
} else return <div>loading...</div>;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -4,14 +4,6 @@ import {IShortWeapon, IWeapon} from "../types/IUnit";
|
|||||||
import {IMod} from "../types/Imod";
|
import {IMod} from "../types/Imod";
|
||||||
import {Irace} from "../types/Irace";
|
import {Irace} from "../types/Irace";
|
||||||
import WeaponShort from "./WeaponFull";
|
import WeaponShort from "./WeaponFull";
|
||||||
import {Typography} from "@mui/material";
|
|
||||||
import {styled} from '@mui/material/styles';
|
|
||||||
|
|
||||||
const SectionTitle = styled(Typography)(({ theme }) => ({
|
|
||||||
fontWeight: 700,
|
|
||||||
mb: 2,
|
|
||||||
fontSize: '1.25rem',
|
|
||||||
}));
|
|
||||||
|
|
||||||
export interface WeaponSlotProps {
|
export interface WeaponSlotProps {
|
||||||
hardpoint: number,
|
hardpoint: number,
|
||||||
@ -41,7 +33,7 @@ const WeaponSlot= (props: WeaponSlotProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<SectionTitle>{header}</SectionTitle>
|
<h3>{header}</h3>
|
||||||
{weaponsSorted.filter(wp => !wp[1].filename.includes("dummy")).map(wp =>
|
{weaponsSorted.filter(wp => !wp[1].filename.includes("dummy")).map(wp =>
|
||||||
|
|
||||||
<div style={{marginLeft: 20}}><Weapon race={props.race} mod={props.mod} isDefault={!haveDummy || wp[1].filename === firstWeapon.filename} weapon={wp[1]} haveReinforceMenu={haveReinforceMenu}/></div>
|
<div style={{marginLeft: 20}}><Weapon race={props.race} mod={props.mod} isDefault={!haveDummy || wp[1].filename === firstWeapon.filename} weapon={wp[1]} haveReinforceMenu={haveReinforceMenu}/></div>
|
||||||
|
|||||||
@ -9,8 +9,7 @@ import {
|
|||||||
TableBody,
|
TableBody,
|
||||||
TableCell,
|
TableCell,
|
||||||
TableContainer,
|
TableContainer,
|
||||||
TableRow,
|
TableRow
|
||||||
Typography
|
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import {IBuilding, IBuildingAddon} from "../../types/IBuilding";
|
import {IBuilding, IBuildingAddon} from "../../types/IBuilding";
|
||||||
import AvTimerOutlinedIcon from "@mui/icons-material/AvTimer";
|
import AvTimerOutlinedIcon from "@mui/icons-material/AvTimer";
|
||||||
@ -18,30 +17,6 @@ import {ExpandMore} from "@mui/icons-material";
|
|||||||
import {IMod} from "../../types/Imod";
|
import {IMod} from "../../types/Imod";
|
||||||
import {getIcon, ModifiersProvidesTable,} from "../ModifiersProvideTable";
|
import {getIcon, ModifiersProvidesTable,} from "../ModifiersProvideTable";
|
||||||
import Required from "../Required";
|
import Required from "../Required";
|
||||||
import {styled} from '@mui/material/styles';
|
|
||||||
import {DescriptionBox} from "../../commons/DescriptionBox";
|
|
||||||
|
|
||||||
const StyledAccordion = styled(Accordion)(({ theme }) => ({
|
|
||||||
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
||||||
borderRadius: '12px',
|
|
||||||
'&:before': { display: 'none' },
|
|
||||||
'&.Mui-expanded': { margin: '0 0 8px 0' },
|
|
||||||
}));
|
|
||||||
|
|
||||||
const StyledPaper = styled(Paper)(({ theme }) => ({
|
|
||||||
background: 'rgba(255, 255, 255, 0.03)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.05)',
|
|
||||||
borderRadius: '12px',
|
|
||||||
overflow: 'hidden',
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-root': {
|
|
||||||
color: 'rgba(255, 255, 255, 0.85)',
|
|
||||||
},
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-head': {
|
|
||||||
color: '#e94560',
|
|
||||||
fontWeight: 600,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
interface IBuildingAddonProps {
|
interface IBuildingAddonProps {
|
||||||
addon: IBuildingAddon,
|
addon: IBuildingAddon,
|
||||||
@ -56,28 +31,27 @@ function BuildingAddon(props: IBuildingAddonProps){
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
return <div className='addon-research-accordion' id={"addon-" + addon.id} ><StyledAccordion>
|
return <div className='addon-research-accordion' id={"addon-" + addon.id} ><Accordion>
|
||||||
<AccordionSummary
|
<AccordionSummary
|
||||||
expandIcon={<ExpandMore sx={{color: '#ffffff'}}/>}
|
expandIcon={<ExpandMore/>}
|
||||||
aria-controls="panel1-content"
|
aria-controls="panel1-content"
|
||||||
sx={{color: '#ffffff'}}
|
|
||||||
>
|
>
|
||||||
<span style={{fontSize: 20, color: '#ffffff'}}>
|
<span style={{fontSize: 20}}>
|
||||||
<img className="sergeantIcon" src={getIcon(addon.icon)}/>
|
<img className="sergeantIcon" src={getIcon(addon.icon)}/>
|
||||||
{addon.name}
|
{addon.name}
|
||||||
</span>
|
</span>
|
||||||
</AccordionSummary>
|
</AccordionSummary>
|
||||||
<AccordionDetails sx={{color: 'rgba(255,255,255,0.85)'}}>
|
<AccordionDetails>
|
||||||
<Grid2 container spacing={2}>
|
<Grid2 container spacing={2}>
|
||||||
<Grid2 size={{xs: 12, md: 4}}>
|
<Grid2 size={{xs: 12, md: 4}}>
|
||||||
<TableContainer component={StyledPaper} elevation={0}>
|
<TableContainer component={Paper}>
|
||||||
<Table size="small" aria-label="a dense table">
|
<Table size="small" aria-label="a dense table">
|
||||||
<TableBody id="unit-stats-table">
|
<TableBody id="unit-stats-table">
|
||||||
<TableRow
|
<TableRow
|
||||||
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
>
|
>
|
||||||
<TableCell component="th" scope="row">Cost</TableCell>
|
<TableCell component="th" scope="row">Cost</TableCell>
|
||||||
<TableCell>
|
<TableCell component="th" scope="row">
|
||||||
{addon.addonCostRequisition > 0 &&
|
{addon.addonCostRequisition > 0 &&
|
||||||
<span> <img style={{verticalAlign: "top"}}
|
<span> <img style={{verticalAlign: "top"}}
|
||||||
src="/images/Resource_requisition.gif"/>
|
src="/images/Resource_requisition.gif"/>
|
||||||
@ -109,9 +83,9 @@ function BuildingAddon(props: IBuildingAddonProps){
|
|||||||
</TableContainer><br/>
|
</TableContainer><br/>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
<Grid2 size={{xs: 12, md: 8}}>
|
<Grid2 size={{xs: 12, md: 8}}>
|
||||||
<DescriptionBox>
|
<div style={{whiteSpace: "pre-wrap"}}>
|
||||||
{addon.description}
|
{addon.description}
|
||||||
</DescriptionBox>
|
</div>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
<ModifiersProvidesTable modifiers={addon.addonModifiers} affectedData={addon.affectedData} modId={props.mod.id} race={building.race}/>
|
<ModifiersProvidesTable modifiers={addon.addonModifiers} affectedData={addon.affectedData} modId={props.mod.id} race={building.race}/>
|
||||||
{addon.addonRequirement !== null &&
|
{addon.addonRequirement !== null &&
|
||||||
@ -121,7 +95,7 @@ function BuildingAddon(props: IBuildingAddonProps){
|
|||||||
</Grid2>
|
</Grid2>
|
||||||
<b className="hotkey">Hotkey: {addon.hotkey}</b>
|
<b className="hotkey">Hotkey: {addon.hotkey}</b>
|
||||||
</AccordionDetails>
|
</AccordionDetails>
|
||||||
</StyledAccordion></div>
|
</Accordion></div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -20,24 +20,6 @@ import React from "react";
|
|||||||
import {IBuilding} from "../../types/IBuilding";
|
import {IBuilding} from "../../types/IBuilding";
|
||||||
import {IResearchShort} from "../../types/IResearchShort";
|
import {IResearchShort} from "../../types/IResearchShort";
|
||||||
import ResearchFull from "./ResearchFull";
|
import ResearchFull from "./ResearchFull";
|
||||||
import {styled} from '@mui/material/styles';
|
|
||||||
|
|
||||||
const StyledAccordion = styled(Accordion)(({ theme }) => ({
|
|
||||||
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
||||||
borderRadius: '12px',
|
|
||||||
'&:before': { display: 'none' },
|
|
||||||
'&.Mui-expanded': { margin: '0 0 8px 0' },
|
|
||||||
}));
|
|
||||||
|
|
||||||
const StyledLink = styled('a')(({ theme }) => ({
|
|
||||||
color: '#e94560',
|
|
||||||
textDecoration: 'none',
|
|
||||||
'&:hover': {
|
|
||||||
color: '#ff6b6b',
|
|
||||||
textDecoration: 'underline',
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
interface IResearchProps {
|
interface IResearchProps {
|
||||||
@ -51,21 +33,20 @@ function Research(props: IResearchProps){
|
|||||||
const research = props.research
|
const research = props.research
|
||||||
const building = props.building
|
const building = props.building
|
||||||
|
|
||||||
return <div className='addon-research-accordion' id={"research-" + research.id}><StyledAccordion TransitionProps={{ unmountOnExit: true, timeout: 100 }}>
|
return <div className='addon-research-accordion' id={"research-" + research.id}><Accordion TransitionProps={{ unmountOnExit: true, timeout: 100 }}>
|
||||||
<AccordionSummary
|
<AccordionSummary
|
||||||
expandIcon={<ExpandMore sx={{color: '#ffffff'}}/>}
|
expandIcon={<ExpandMore/>}
|
||||||
aria-controls="panel1-content"
|
aria-controls="panel1-content"
|
||||||
sx={{color: '#ffffff'}}
|
|
||||||
>
|
>
|
||||||
<span style={{fontSize: 20, color: '#ffffff'}}>
|
<span style={{fontSize: 20}}>
|
||||||
<img className="sergeantIcon" src={getIcon(research.icon)}/>
|
<img className="sergeantIcon" src={getIcon(research.icon)}/>
|
||||||
{research.name}
|
{research.name}
|
||||||
</span>
|
</span>
|
||||||
</AccordionSummary>
|
</AccordionSummary>
|
||||||
<AccordionDetails sx={{color: 'rgba(255,255,255,0.85)'}}>
|
<AccordionDetails>
|
||||||
<ResearchFull id={research.id} building={building}/>
|
<ResearchFull id={research.id} building={building}/>
|
||||||
</AccordionDetails>
|
</AccordionDetails>
|
||||||
</StyledAccordion></div>
|
</Accordion></div>
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,12 +55,12 @@ export function renderAffectedResearches(researches: IResearchShort[], modId: nu
|
|||||||
function researchLink(rs: IResearchShort) {
|
function researchLink(rs: IResearchShort) {
|
||||||
return <span><img style={{verticalAlign: "top", height: 25}}
|
return <span><img style={{verticalAlign: "top", height: 25}}
|
||||||
src={getIcon(rs.icon)}/>
|
src={getIcon(rs.icon)}/>
|
||||||
<StyledLink href={`/mod/${modId}/race/${raceId}/building/${rs.buildingId}#research-${rs.id}`}>
|
<a href={`/mod/${modId}/race/${raceId}/building/${rs.buildingId}#research-${rs.id}`}>
|
||||||
{rs.name}
|
{rs.name}
|
||||||
</StyledLink></span>
|
</a></span>
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div style={{color: 'rgba(255, 255, 255, 0.85)'}}> {researches.map(rs =>
|
return <div> {researches.map(rs =>
|
||||||
rs.buildingId == null ? <span key={rs.id}></span> :
|
rs.buildingId == null ? <span key={rs.id}></span> :
|
||||||
<span key={rs.id}>Research affect: {researchLink(rs)}<br/></span>
|
<span key={rs.id}>Research affect: {researchLink(rs)}<br/></span>
|
||||||
)}</div>
|
)}</div>
|
||||||
|
|||||||
@ -10,8 +10,7 @@ import {
|
|||||||
TableBody,
|
TableBody,
|
||||||
TableCell,
|
TableCell,
|
||||||
TableContainer,
|
TableContainer,
|
||||||
TableRow,
|
TableRow
|
||||||
Typography
|
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import {ExpandMore} from "@mui/icons-material";
|
import {ExpandMore} from "@mui/icons-material";
|
||||||
import {getIcon, ModifiersProvidesTable} from "../ModifiersProvideTable";
|
import {getIcon, ModifiersProvidesTable} from "../ModifiersProvideTable";
|
||||||
@ -22,22 +21,6 @@ import {IBuilding} from "../../types/IBuilding";
|
|||||||
import {IResearchShort} from "../../types/IResearchShort";
|
import {IResearchShort} from "../../types/IResearchShort";
|
||||||
import {ResearchUrl, WeaponUrl} from "../../core/api";
|
import {ResearchUrl, WeaponUrl} from "../../core/api";
|
||||||
import {IWeapon} from "../../types/IUnit";
|
import {IWeapon} from "../../types/IUnit";
|
||||||
import {styled} from '@mui/material/styles';
|
|
||||||
import {DescriptionBox} from "../../commons/DescriptionBox";
|
|
||||||
|
|
||||||
const StyledPaper = styled(Paper)(({ theme }) => ({
|
|
||||||
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
||||||
borderRadius: '12px',
|
|
||||||
overflow: 'hidden',
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-root': {
|
|
||||||
color: 'rgba(255, 255, 255, 0.9)',
|
|
||||||
},
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-head': {
|
|
||||||
color: '#e94560',
|
|
||||||
fontWeight: 600,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
interface IResearchFull {
|
interface IResearchFull {
|
||||||
@ -71,14 +54,14 @@ function ResearchFull(props: { id: number, building: IBuilding }){
|
|||||||
|
|
||||||
<Grid2 container spacing={2}>
|
<Grid2 container spacing={2}>
|
||||||
<Grid2 size={{xs: 12, md: 4}}>
|
<Grid2 size={{xs: 12, md: 4}}>
|
||||||
<TableContainer component={StyledPaper} elevation={0}>
|
<TableContainer component={Paper}>
|
||||||
<Table size="small" aria-label="a dense table">
|
<Table size="small" aria-label="a dense table">
|
||||||
<TableBody id="unit-stats-table">
|
<TableBody id="unit-stats-table">
|
||||||
<TableRow
|
<TableRow
|
||||||
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
>
|
>
|
||||||
<TableCell component="th" scope="row">Cost</TableCell>
|
<TableCell component="th" scope="row">Cost</TableCell>
|
||||||
<TableCell>
|
<TableCell component="th" scope="row">
|
||||||
{research.costRequisition > 0 &&
|
{research.costRequisition > 0 &&
|
||||||
<span> <img style={{verticalAlign: "top"}}
|
<span> <img style={{verticalAlign: "top"}}
|
||||||
src="/images/Resource_requisition.gif"/>
|
src="/images/Resource_requisition.gif"/>
|
||||||
@ -110,9 +93,9 @@ function ResearchFull(props: { id: number, building: IBuilding }){
|
|||||||
</TableContainer><br/>
|
</TableContainer><br/>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
<Grid2 size={{xs: 12, md: 8}}>
|
<Grid2 size={{xs: 12, md: 8}}>
|
||||||
<DescriptionBox>
|
<div style={{whiteSpace: "pre-wrap"}}>
|
||||||
{research.description}
|
{research.description}
|
||||||
</DescriptionBox>
|
</div>
|
||||||
|
|
||||||
</Grid2>
|
</Grid2>
|
||||||
<Grid2 size={{xs: 12, md: 12}}>
|
<Grid2 size={{xs: 12, md: 12}}>
|
||||||
@ -126,7 +109,7 @@ function ResearchFull(props: { id: number, building: IBuilding }){
|
|||||||
</Grid2>
|
</Grid2>
|
||||||
<b className="hotkey">Hotkey: {research.hotkey}</b>
|
<b className="hotkey">Hotkey: {research.hotkey}</b>
|
||||||
</div>
|
</div>
|
||||||
} else return <div style={{color: 'rgba(255, 255, 255, 0.5)'}}>loading...</div>
|
} else return <div>loading...</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ResearchFull;
|
export default ResearchFull;
|
||||||
|
|||||||
@ -1,14 +0,0 @@
|
|||||||
import {Button, Link} from "@mui/material";
|
|
||||||
import {styled} from '@mui/material/styles';
|
|
||||||
|
|
||||||
export const BackButton = styled(Button)(({ theme }) => ({
|
|
||||||
marginBottom: theme.spacing(3),
|
|
||||||
color: '#e94560BB',
|
|
||||||
borderColor: 'rgba(233, 69, 96, 0.5)',
|
|
||||||
textTransform: 'none',
|
|
||||||
fontWeight: 600,
|
|
||||||
'&:hover': {
|
|
||||||
borderColor: '#e94560',
|
|
||||||
backgroundColor: 'rgba(233, 69, 96, 0.1)',
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
import {styled} from '@mui/material/styles';
|
|
||||||
|
|
||||||
export const DescriptionBox = styled('div')(({ theme }) => ({
|
|
||||||
color: 'rgba(255, 255, 255, 0.85)',
|
|
||||||
lineHeight: 1.7,
|
|
||||||
fontSize: '0.95rem',
|
|
||||||
padding: theme.spacing(3),
|
|
||||||
background: 'rgba(255, 255, 255, 0.03)',
|
|
||||||
borderRadius: '12px',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.05)',
|
|
||||||
whiteSpace: 'pre-wrap',
|
|
||||||
}));
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
import {Link} from "@mui/material";
|
|
||||||
import {styled} from '@mui/material/styles';
|
|
||||||
|
|
||||||
export const StyledLink = styled(Link)(({ theme }) => ({
|
|
||||||
color: '#e94560BB',
|
|
||||||
textDecoration: 'none',
|
|
||||||
transition: 'all 0.2s ease',
|
|
||||||
'&:hover': {
|
|
||||||
color: '#ff6b6bBB',
|
|
||||||
textDecoration: 'underline',
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
@ -1,43 +1,13 @@
|
|||||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap');
|
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||||
sans-serif;
|
sans-serif;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
background-color: #0a0a0a;
|
|
||||||
color: rgba(255, 255, 255, 0.85);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
code {
|
code {
|
||||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||||
monospace;
|
monospace;
|
||||||
background: rgba(255, 255, 255, 0.1);
|
|
||||||
padding: 2px 6px;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
* {
|
|
||||||
scrollbar-width: thin;
|
|
||||||
scrollbar-color: #e94560 #1a1a2e;
|
|
||||||
}
|
|
||||||
|
|
||||||
*::-webkit-scrollbar {
|
|
||||||
width: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
*::-webkit-scrollbar-track {
|
|
||||||
background: #1a1a2e;
|
|
||||||
}
|
|
||||||
|
|
||||||
*::-webkit-scrollbar-thumb {
|
|
||||||
background-color: #e94560;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,9 +5,6 @@ import {IShortWeapon} from "../types/IUnit";
|
|||||||
import '../css/Building.css'
|
import '../css/Building.css'
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Box,
|
|
||||||
Container,
|
|
||||||
Divider,
|
|
||||||
Grid2,
|
Grid2,
|
||||||
Link,
|
Link,
|
||||||
ListItem,
|
ListItem,
|
||||||
@ -15,10 +12,11 @@ import {
|
|||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
TableCell,
|
TableCell,
|
||||||
|
TableContainer,
|
||||||
TableRow,
|
TableRow,
|
||||||
Tooltip,
|
Tooltip
|
||||||
Typography, LinearProgress
|
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
|
import {ArrowBack} from "@mui/icons-material";
|
||||||
import ArmorType from "../classes/ArmorType";
|
import ArmorType from "../classes/ArmorType";
|
||||||
import AvTimerOutlinedIcon from '@mui/icons-material/AvTimer';
|
import AvTimerOutlinedIcon from '@mui/icons-material/AvTimer';
|
||||||
import WeaponSlot from "../classes/WeaponSlot";
|
import WeaponSlot from "../classes/WeaponSlot";
|
||||||
@ -33,31 +31,6 @@ import Required from "../classes/Required";
|
|||||||
import {ModifiersProvidesTable} from "../classes/ModifiersProvideTable";
|
import {ModifiersProvidesTable} from "../classes/ModifiersProvideTable";
|
||||||
import Ability from "../classes/Ability";
|
import Ability from "../classes/Ability";
|
||||||
import DeathExplosion from "../classes/DeathExplosion";
|
import DeathExplosion from "../classes/DeathExplosion";
|
||||||
import {styled} from '@mui/material/styles';
|
|
||||||
import {DescriptionBox} from "../commons/DescriptionBox";
|
|
||||||
import {ArrowBack} from "@mui/icons-material";
|
|
||||||
import {BackButton} from "../commons/BackButton";
|
|
||||||
|
|
||||||
|
|
||||||
const SectionTitle = styled(Typography)(({ theme }) => ({
|
|
||||||
fontWeight: 700,
|
|
||||||
mb: 2,
|
|
||||||
fontSize: '1.25rem',
|
|
||||||
}));
|
|
||||||
|
|
||||||
const StatsPaper = styled(Paper)(({ theme }) => ({
|
|
||||||
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
||||||
borderRadius: '12px',
|
|
||||||
overflow: 'hidden',
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-root': {
|
|
||||||
color: 'rgba(255, 255, 255, 0.9)',
|
|
||||||
},
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-head': {
|
|
||||||
color: '#e94560',
|
|
||||||
fontWeight: 600,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
interface UintPageState {
|
interface UintPageState {
|
||||||
building: IBuilding,
|
building: IBuilding,
|
||||||
@ -66,30 +39,18 @@ interface UintPageState {
|
|||||||
|
|
||||||
function Unit (unit: IUnitShort, modId: number, raceId: String) {
|
function Unit (unit: IUnitShort, modId: number, raceId: String) {
|
||||||
|
|
||||||
return (<Grid2 key={unit.id} size={{xs: 12, md: 3}}>
|
return (<Grid2 key={unit.id} size={{xs: 12, md: 3}}><Link href={"/mod/" + modId + "/race/" + raceId + "/unit/" + unit.id}><ListItem>
|
||||||
<Link href={"/mod/" + modId + "/race/" + raceId + "/unit/" + unit.id} sx={{color: 'rgba(255,255,255,0.85)', textDecoration: 'none', '&:hover': {color: '#e94560'}}}>
|
|
||||||
<ListItem sx={{
|
|
||||||
color: 'rgba(255,255,255,0.85)',
|
|
||||||
padding: '8px 12px',
|
|
||||||
background: 'rgba(255,255,255,0.03)',
|
|
||||||
borderRadius: '8px',
|
|
||||||
border: '1px solid rgba(255,255,255,0.05)',
|
|
||||||
transition: 'all 0.2s ease',
|
|
||||||
'&:hover': { background: 'rgba(233, 69, 96, 0.1)', borderColor: 'rgba(233, 69, 96, 0.3)' }
|
|
||||||
}}>
|
|
||||||
{unit.icon && <img className="unitIcon" src={IconUrl + unit.icon.replaceAll('\\', '/')}/> }
|
{unit.icon && <img className="unitIcon" src={IconUrl + unit.icon.replaceAll('\\', '/')}/> }
|
||||||
{unit.name}
|
{unit.name}
|
||||||
{unit.canDetect && <span> <img style={{verticalAlign: "top"}}
|
{unit.canDetect && <span> <img style={{verticalAlign: "top"}}
|
||||||
src="/images/DETECT_YES.webp"/></span>}
|
src="/images/DETECT_YES.webp"/></span>}
|
||||||
</ListItem>
|
</ListItem></Link></Grid2>)
|
||||||
</Link>
|
|
||||||
</Grid2>)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function Building(building: IBuilding, mod: IMod) {
|
function Building(building: IBuilding, mod: IMod) {
|
||||||
|
|
||||||
document.title = building.name + " — " + mod.name
|
document.title = building.name
|
||||||
|
|
||||||
|
|
||||||
let mapBuildingWeapons: Map<number, Map<number, IShortWeapon>> = new Map();
|
let mapBuildingWeapons: Map<number, Map<number, IShortWeapon>> = new Map();
|
||||||
@ -111,35 +72,21 @@ function Building(building: IBuilding, mod: IMod) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<div>
|
||||||
<Box sx={{ mb: 3 }}>
|
<h1>{mod.name} ({mod.version})</h1>
|
||||||
<Typography variant="h4" component="h2" sx={{
|
<h2>{building.icon &&
|
||||||
fontWeight: 800,
|
<img className="unitIcon" src={IconUrl + building.icon.replaceAll('\\', '/')}/>} {buildingName} </h2>
|
||||||
mb: 1,
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: 2,
|
|
||||||
}}>
|
|
||||||
{building.icon &&
|
|
||||||
<img className="unitIcon" src={IconUrl + building.icon.replaceAll('\\', '/')}/>}
|
|
||||||
{buildingName}
|
|
||||||
</Typography>
|
|
||||||
<Typography variant="subtitle1" sx={{
|
|
||||||
color: 'rgba(255, 255, 255, 0.6)',
|
|
||||||
fontWeight: 500,
|
|
||||||
}}>
|
|
||||||
{mod.name} ({mod.version})
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Grid2 container spacing={3}>
|
<Grid2 container spacing={2}>
|
||||||
<Grid2 size={{xs: 12, md: 4}}>
|
<Grid2 size={{xs: 12, md: 4}}>
|
||||||
<StatsPaper elevation={0}>
|
<TableContainer component={Paper}>
|
||||||
<Table size="small" aria-label="a dense table">
|
<Table size="small" aria-label="a dense table">
|
||||||
<TableBody id="unit-stats-table">
|
<TableBody id="unit-stats-table">
|
||||||
<TableRow>
|
<TableRow
|
||||||
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
|
>
|
||||||
<TableCell component="th" scope="row">Cost</TableCell>
|
<TableCell component="th" scope="row">Cost</TableCell>
|
||||||
<TableCell>
|
<TableCell component="th" scope="row">
|
||||||
{building.buildCostRequisition > 0 &&
|
{building.buildCostRequisition > 0 &&
|
||||||
<span> <img style={{verticalAlign: "top"}}
|
<span> <img style={{verticalAlign: "top"}}
|
||||||
src="/images/Resource_requisition.gif"/>
|
src="/images/Resource_requisition.gif"/>
|
||||||
@ -184,40 +131,50 @@ function Building(building: IBuilding, mod: IMod) {
|
|||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
}
|
}
|
||||||
<TableRow>
|
<TableRow
|
||||||
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
|
>
|
||||||
<TableCell component="th" scope="row">Armor type</TableCell>
|
<TableCell component="th" scope="row">Armor type</TableCell>
|
||||||
<TableCell>
|
<TableCell component="th" scope="row">
|
||||||
{building.armorType2 == null ? <ArmorType name={building.armorType.name} compact={false}/>
|
{building.armorType2 == null ? <ArmorType name={building.armorType.name} compact={false}/>
|
||||||
: <Tooltip title={"upgrade/debuff can turns to " + building.armorType2.name}><span><ArmorType name={building.armorType.name} compact={false}/></span></Tooltip> }
|
: <Tooltip title={"upgrade/debuff can turns to " + building.armorType2.name}><span><ArmorType name={building.armorType.name} compact={false}/></span></Tooltip> }
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow
|
||||||
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
|
>
|
||||||
<TableCell component="th" scope="row">Health</TableCell>
|
<TableCell component="th" scope="row">Health</TableCell>
|
||||||
<TableCell>
|
<TableCell component="th" scope="row">
|
||||||
<span><img style={{verticalAlign: "top"}}
|
<span><img style={{verticalAlign: "top"}}
|
||||||
src="/images/Health_icon.webp"/>
|
src="/images/Health_icon.webp"/>
|
||||||
{building.health} {building.healthRegeneration > 0 &&
|
{building.health} {building.healthRegeneration > 0 &&
|
||||||
<span>+{building.healthRegeneration}/s</span>} </span>
|
<span>+{building.healthRegeneration}/s</span>} </span>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow
|
||||||
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
|
>
|
||||||
<TableCell component="th" scope="row">Sight</TableCell>
|
<TableCell component="th" scope="row">Sight</TableCell>
|
||||||
<TableCell>
|
<TableCell component="th" scope="row">
|
||||||
<Vision sight={building.sightRadius} detect={building.detectRadius}/>
|
<Vision sight={building.sightRadius} detect={building.detectRadius}/>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
<TableRow
|
||||||
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
|
>
|
||||||
<TableCell component="th" scope="row">Repair max</TableCell>
|
<TableCell component="th" scope="row">Repair max</TableCell>
|
||||||
<TableCell>{building.repairMax}</TableCell>
|
<TableCell component="th" scope="row">
|
||||||
|
{building.repairMax}
|
||||||
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</StatsPaper>
|
</TableContainer>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
<Grid2 size={{xs: 12, md: 8}}>
|
<Grid2 size={8}>
|
||||||
<DescriptionBox>
|
<div style={{whiteSpace: "pre-wrap"}}>
|
||||||
{building.description}
|
{building.description}
|
||||||
</DescriptionBox>
|
</div>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
{building.requirements !== null &&
|
{building.requirements !== null &&
|
||||||
<Grid2 size={{xs: 12, md: 12}}>
|
<Grid2 size={{xs: 12, md: 12}}>
|
||||||
@ -225,11 +182,11 @@ function Building(building: IBuilding, mod: IMod) {
|
|||||||
</Grid2>}
|
</Grid2>}
|
||||||
{building.modifiers.length > 0 &&
|
{building.modifiers.length > 0 &&
|
||||||
<Grid2 size={{xs: 12, md: 12}} >
|
<Grid2 size={{xs: 12, md: 12}} >
|
||||||
<SectionTitle>Affected on</SectionTitle>
|
<h3>Affected on</h3>
|
||||||
<ModifiersProvidesTable modifiers={building.modifiers} race={building.race} modId={building.modId} affectedData={building.affectedData} />
|
<ModifiersProvidesTable modifiers={building.modifiers} race={building.race} modId={building.modId} affectedData={building.affectedData} />
|
||||||
</Grid2>}
|
</Grid2>}
|
||||||
{building.units.length > 0 && <Grid2 size={12}>
|
{building.units.length > 0 && <Grid2 size={12}>
|
||||||
<SectionTitle>Unit production</SectionTitle>
|
<h3>Unit production</h3>
|
||||||
<Grid2 container spacing={2}>
|
<Grid2 container spacing={2}>
|
||||||
{building.units.map(unit =>
|
{building.units.map(unit =>
|
||||||
Unit(unit, mod.id, building.race.id)
|
Unit(unit, mod.id, building.race.id)
|
||||||
@ -237,7 +194,7 @@ function Building(building: IBuilding, mod: IMod) {
|
|||||||
</Grid2>
|
</Grid2>
|
||||||
</Grid2>}
|
</Grid2>}
|
||||||
{building.abilities.length > 0 && <Grid2 size={12}>
|
{building.abilities.length > 0 && <Grid2 size={12}>
|
||||||
<SectionTitle>Abilities</SectionTitle>
|
<h3>Abilities</h3>
|
||||||
{building.abilities.map(a =>
|
{building.abilities.map(a =>
|
||||||
<Ability mod={mod} ability={a} race={building.race}/>
|
<Ability mod={mod} ability={a} race={building.race}/>
|
||||||
)}
|
)}
|
||||||
@ -250,13 +207,13 @@ function Building(building: IBuilding, mod: IMod) {
|
|||||||
</Grid2>
|
</Grid2>
|
||||||
}
|
}
|
||||||
{building.addons.length > 0 && <Grid2 size={12}>
|
{building.addons.length > 0 && <Grid2 size={12}>
|
||||||
<SectionTitle>Addons</SectionTitle>
|
<h3>Addons</h3>
|
||||||
{building.addons.map(b =>
|
{building.addons.map(b =>
|
||||||
<BuildingAddon mod={mod} addon={b} building={building}/>
|
<BuildingAddon mod={mod} addon={b} building={building}/>
|
||||||
)}
|
)}
|
||||||
</Grid2> }
|
</Grid2> }
|
||||||
{building.researches.length > 0 && <Grid2 size={12}>
|
{building.researches.length > 0 && <Grid2 size={12}>
|
||||||
<SectionTitle>Researches</SectionTitle>
|
<h3>Researches</h3>
|
||||||
{building.researches.map(r =>
|
{building.researches.map(r =>
|
||||||
<Research key={r.id} research={r} building={building} mod={mod}/>
|
<Research key={r.id} research={r} building={building} mod={mod}/>
|
||||||
)}
|
)}
|
||||||
@ -270,12 +227,10 @@ function Building(building: IBuilding, mod: IMod) {
|
|||||||
{renderAffectedResearches(building.affectedResearches, mod.id, building.race.id)}
|
{renderAffectedResearches(building.affectedResearches, mod.id, building.race.id)}
|
||||||
</Grid2>
|
</Grid2>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
<Box sx={{ mt: 3, mb: 2, color: '#e94560', fontWeight: 600, fontSize: '0.85rem' }}>
|
<b className="hotkey">Hotkey: {building.hotkey}</b>
|
||||||
Hotkey: {building.hotkey}
|
<hr/>
|
||||||
</Box>
|
|
||||||
<Divider sx={{ my: 3, borderColor: 'rgba(255, 255, 255, 0.1)' }} />
|
|
||||||
<UnitsTable modId={mod.id}/>
|
<UnitsTable modId={mod.id}/>
|
||||||
</Box>)
|
</div>)
|
||||||
}
|
}
|
||||||
|
|
||||||
class BuildingPage extends React.Component<any, UintPageState> {
|
class BuildingPage extends React.Component<any, UintPageState> {
|
||||||
@ -301,24 +256,12 @@ class BuildingPage extends React.Component<any, UintPageState> {
|
|||||||
if (this.state != null && this.state.building != null && this.state.mod != null) {
|
if (this.state != null && this.state.building != null && this.state.mod != null) {
|
||||||
const backRef = "/mod/" + this.props.match.params.modId + "/race/" + this.props.match.params.raceId
|
const backRef = "/mod/" + this.props.match.params.modId + "/race/" + this.props.match.params.raceId
|
||||||
|
|
||||||
return (
|
return <div><a href={backRef}><Button id="back-button" variant="contained"
|
||||||
<Container maxWidth="lg" sx={{ py: 4 }}>
|
startIcon={<ArrowBack/>}> Back</Button></a>
|
||||||
<BackButton
|
|
||||||
variant="outlined"
|
|
||||||
startIcon={<ArrowBack/>}
|
|
||||||
href={backRef}
|
|
||||||
>
|
|
||||||
Back to race
|
|
||||||
</BackButton>
|
|
||||||
{Building(this.state.building, this.state.mod)}
|
{Building(this.state.building, this.state.mod)}
|
||||||
</Container>
|
</div>;
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
return (
|
return "loading...";
|
||||||
<Box sx={{ display: 'flex', justifyContent: 'center', py: 8 }}>
|
|
||||||
<LinearProgress sx={{ width: '200px' }} />
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,48 +1,17 @@
|
|||||||
import {AvailableMods, AvailableRacesPart, AvailableUnits, IconUrl} from "../core/api";
|
import {AvailableMods, AvailableRacesPart, AvailableUnits, IconUrl} from "../core/api";
|
||||||
import React, { useState } from "react";
|
import React, {useEffect, useRef, useState} from "react";
|
||||||
|
import {NavLink, useLocation, useParams} from "react-router-dom";
|
||||||
import {withRouter} from "../core/withrouter";
|
import {withRouter} from "../core/withrouter";
|
||||||
import {IMod} from "../types/Imod";
|
import {IMod} from "../types/Imod";
|
||||||
import {
|
import {Irace} from "../types/Irace";
|
||||||
ArrowBack,
|
import {Button, ListItem, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow} from "@mui/material";
|
||||||
} from "@mui/icons-material";
|
import {ArrowBack} from "@mui/icons-material";
|
||||||
import {
|
import {IRaceUnits, IUnitShort} from "../types/IUnitShort";
|
||||||
Box,
|
|
||||||
Button,
|
|
||||||
Container,
|
|
||||||
Paper,
|
|
||||||
Typography,
|
|
||||||
Divider,
|
|
||||||
LinearProgress
|
|
||||||
} from "@mui/material";
|
|
||||||
import {styled} from '@mui/material/styles';
|
|
||||||
import UnitsTable from "../classes/UnitsTable";
|
import UnitsTable from "../classes/UnitsTable";
|
||||||
import {BackButton} from "../commons/BackButton";
|
|
||||||
|
|
||||||
|
|
||||||
// Styled components
|
|
||||||
const PageHeader = styled(Paper)(({ theme }) => ({
|
|
||||||
padding: theme.spacing(4, 4),
|
|
||||||
marginBottom: theme.spacing(4),
|
|
||||||
background: 'linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%)',
|
|
||||||
borderRadius: '16px',
|
|
||||||
position: 'relative',
|
|
||||||
overflow: 'hidden',
|
|
||||||
'&::before': {
|
|
||||||
content: '""',
|
|
||||||
position: 'absolute',
|
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
bottom: 0,
|
|
||||||
background: 'radial-gradient(circle at 30% 50%, rgba(233, 69, 96, 0.1) 0%, transparent 50%)',
|
|
||||||
pointerEvents: 'none',
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
interface ModPageState {
|
interface ModPageState {
|
||||||
mod: IMod | null,
|
mod: IMod,
|
||||||
loading: boolean,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -51,80 +20,31 @@ class ModPage extends React.Component<any, ModPageState> {
|
|||||||
|
|
||||||
constructor(props: any) {
|
constructor(props: any) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
|
||||||
mod: null,
|
|
||||||
loading: true
|
|
||||||
};
|
|
||||||
|
|
||||||
fetch(AvailableMods + "/" + this.props.match.params.modId)
|
fetch(AvailableMods + "/" + this.props.match.params.modId)
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
.then((res: IMod) => {
|
.then((res: IMod) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
mod: res,
|
mod : res
|
||||||
loading: false
|
|
||||||
});
|
});
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
this.setState({ loading: false });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (this.state.loading) {
|
|
||||||
return (
|
|
||||||
<Container maxWidth="lg" sx={{ py: 4 }}>
|
|
||||||
<LinearProgress sx={{ width: '200px', mx: 'auto', display: 'block' }} />
|
|
||||||
</Container>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(this.state != null && this.state.mod != null ){
|
if(this.state != null && this.state.mod != null ){
|
||||||
document.title = this.state.mod.name + " — ModWiki";
|
|
||||||
|
|
||||||
return (
|
document.title = this.state.mod.name
|
||||||
<Container maxWidth="lg" sx={{ py: 4 }}>
|
|
||||||
<BackButton
|
|
||||||
variant="outlined"
|
|
||||||
startIcon={<ArrowBack/>}
|
|
||||||
href="/"
|
|
||||||
>
|
|
||||||
Back to mods list
|
|
||||||
</BackButton>
|
|
||||||
|
|
||||||
<PageHeader elevation={0}>
|
return <div>
|
||||||
<Typography variant="h3" component="h1" sx={{
|
<a href="/"><Button id="back-button" variant="contained"
|
||||||
fontWeight: 800,
|
startIcon={<ArrowBack/>}> Back</Button></a>
|
||||||
mb: 1,
|
<h1>{this.state.mod.name} ({this.state.mod.version})</h1>
|
||||||
background: 'linear-gradient(135deg, #ffffff 0%, #e0e0e0 100%)',
|
|
||||||
WebkitBackgroundClip: 'text',
|
|
||||||
WebkitTextFillColor: 'transparent',
|
|
||||||
}}>
|
|
||||||
{this.state.mod.name}
|
|
||||||
</Typography>
|
|
||||||
<Typography variant="h6" sx={{
|
|
||||||
color: 'rgba(255, 255, 255, 0.7)',
|
|
||||||
fontWeight: 500,
|
|
||||||
}}>
|
|
||||||
Version {this.state.mod.version}
|
|
||||||
</Typography>
|
|
||||||
</PageHeader>
|
|
||||||
|
|
||||||
<Divider sx={{ my: 4, borderColor: 'rgba(255, 255, 255, 0.1)' }} />
|
|
||||||
|
|
||||||
<Box>
|
|
||||||
<UnitsTable modId={this.state.mod.id}/>
|
<UnitsTable modId={this.state.mod.id}/>
|
||||||
</Box>
|
</div>;
|
||||||
</Container>
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
return (
|
return "";
|
||||||
<Container maxWidth="lg" sx={{ py: 8, textAlign: 'center' }}>
|
|
||||||
<Typography variant="h5" sx={{ color: 'rgba(255, 255, 255, 0.5)' }}>
|
|
||||||
Mod not found
|
|
||||||
</Typography>
|
|
||||||
</Container>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,272 +1,49 @@
|
|||||||
import {AvailableMods} from "../core/api";
|
import {AvailableMods} from "../core/api";
|
||||||
import React from "react";
|
import React, {useEffect, useState} from "react";
|
||||||
import {NavLink} from "react-router-dom";
|
import {NavLink} from "react-router-dom";
|
||||||
import {IMod} from "../types/Imod";
|
import {IMod} from "../types/Imod";
|
||||||
import {
|
|
||||||
Box,
|
|
||||||
Container,
|
|
||||||
Typography,
|
|
||||||
Grid,
|
|
||||||
Card,
|
|
||||||
CardContent,
|
|
||||||
CardActions,
|
|
||||||
Chip,
|
|
||||||
Button,
|
|
||||||
Divider,
|
|
||||||
useTheme,
|
|
||||||
Paper,
|
|
||||||
LinearProgress
|
|
||||||
} from "@mui/material";
|
|
||||||
import { styled } from '@mui/material/styles';
|
|
||||||
|
|
||||||
// Styled components
|
function Mods (mods: IMod[]) {
|
||||||
const PageHeader = styled(Paper)(({ theme }) => ({
|
|
||||||
padding: theme.spacing(6, 4),
|
|
||||||
marginBottom: theme.spacing(6),
|
|
||||||
background: 'linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%)',
|
|
||||||
borderRadius: '16px',
|
|
||||||
position: 'relative',
|
|
||||||
overflow: 'hidden',
|
|
||||||
'&::before': {
|
|
||||||
content: '""',
|
|
||||||
position: 'absolute',
|
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
bottom: 0,
|
|
||||||
background: 'radial-gradient(circle at 30% 50%, rgba(233, 69, 96, 0.1) 0%, transparent 50%)',
|
|
||||||
pointerEvents: 'none',
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const ModCard = styled(Card)(({ theme }) => ({
|
let mapWithModVersions: Map<String, IMod[]> = new Map();
|
||||||
height: '100%',
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
||||||
borderRadius: '16px',
|
|
||||||
transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
|
|
||||||
position: 'relative',
|
|
||||||
overflow: 'hidden',
|
|
||||||
'&::before': {
|
|
||||||
content: '""',
|
|
||||||
position: 'absolute',
|
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
height: '3px',
|
|
||||||
background: 'linear-gradient(90deg, #e94560 0%, #ff6b6b 100%)',
|
|
||||||
transform: 'scaleX(0)',
|
|
||||||
transition: 'transform 0.3s ease',
|
|
||||||
},
|
|
||||||
'&:hover': {
|
|
||||||
transform: 'translateY(-8px)',
|
|
||||||
boxShadow: '0 20px 40px rgba(233, 69, 96, 0.2)',
|
|
||||||
borderColor: 'rgba(233, 69, 96, 0.3)',
|
|
||||||
'&::before': {
|
|
||||||
transform: 'scaleX(1)',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const VersionLink = styled(NavLink)(({ theme }) => ({
|
mods.forEach( mod => {
|
||||||
display: 'flex',
|
const versionList = mapWithModVersions.get(mod.name)
|
||||||
alignItems: 'center',
|
|
||||||
padding: theme.spacing(1.5, 2),
|
|
||||||
marginBottom: theme.spacing(1),
|
|
||||||
background: 'rgba(255, 255, 255, 0.05)',
|
|
||||||
borderRadius: '10px',
|
|
||||||
textDecoration: 'none',
|
|
||||||
color: 'inherit',
|
|
||||||
transition: 'all 0.2s ease',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
||||||
'&:hover': {
|
|
||||||
background: 'rgba(233, 69, 96, 0.15)',
|
|
||||||
borderColor: 'rgba(233, 69, 96, 0.3)',
|
|
||||||
transform: 'translateX(4px)',
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
interface ModsProps {
|
|
||||||
mods: IMod[];
|
|
||||||
}
|
|
||||||
|
|
||||||
function Mods({ mods }: ModsProps) {
|
|
||||||
const theme = useTheme();
|
|
||||||
|
|
||||||
// Sort all mods by order, then group by name
|
|
||||||
const sortedMods = [...mods].sort((a, b) => a.order - b.order);
|
|
||||||
|
|
||||||
const mapWithModVersions = new Map<String, IMod[]>();
|
|
||||||
sortedMods.forEach(mod => {
|
|
||||||
const versionList = mapWithModVersions.get(mod.name);
|
|
||||||
if(versionList == null){
|
if(versionList == null){
|
||||||
mapWithModVersions.set(mod.name, [mod]);
|
mapWithModVersions.set(mod.name, new Array(mod))
|
||||||
} else {
|
} else {
|
||||||
versionList.push(mod);
|
versionList.push(mod)
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
const getLatestVersion = (modName: String) => {
|
|
||||||
const sameMods = mapWithModVersions.get(modName) ?? [];
|
|
||||||
// The latest version is the one with the maximum id
|
|
||||||
const latest = sameMods.reduce((max, mod) => mod.id > max.id ? mod : max, sameMods[0]);
|
|
||||||
const nonBetaMods = sameMods.filter(m => !m.isBeta);
|
|
||||||
const betaMods = sameMods.filter(m => m.isBeta);
|
|
||||||
return {
|
|
||||||
latest: latest,
|
|
||||||
allVersions: sameMods,
|
|
||||||
hasBeta: betaMods.length > 0,
|
|
||||||
betaVersion: betaMods[0]
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
function ModCardComponent(modName: String, index: number) {
|
|
||||||
const sameMods = mapWithModVersions.get(modName) ?? [];
|
function Mod (modName: String) {
|
||||||
const { latest, hasBeta, betaVersion } = getLatestVersion(modName);
|
let sameMods = mapWithModVersions.get(modName) ?? []
|
||||||
|
|
||||||
|
let lastBeta = sameMods.filter((m) => m.isBeta).reverse()[0]
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<ModCard sx={{ animationDelay: `${index * 100}ms` }}>
|
<div>
|
||||||
<CardContent sx={{ flexGrow: 1, p: 3 }}>
|
<h1>{modName}</h1>
|
||||||
<Box sx={{ mb: 2 }}>
|
{modName == "Unification new races" && <ul><a href="https://dawn-of-war-unification-mod.fandom.com/">Official unification wiki</a></ul>}
|
||||||
<Typography variant="h5" component="h2" sx={{
|
{sameMods.filter((m) => !m.isBeta).map(mod =>
|
||||||
fontWeight: 700,
|
<ul><NavLink state={mod.id} to= {"/mod/" + mod.id} >{mod.version}</NavLink></ul>)}
|
||||||
mb: 1,
|
{sameMods.find((m) => m.isBeta) != null && <div><i>Beta versions:</i></div>}
|
||||||
background: 'linear-gradient(135deg, #ffffff 0%, #e0e0e0 100%)',
|
{lastBeta != null &&
|
||||||
WebkitBackgroundClip: 'text',
|
<ul><NavLink state={lastBeta.id} to={"/mod/" + lastBeta.id}>{lastBeta.version}</NavLink></ul>
|
||||||
WebkitTextFillColor: 'transparent',
|
}
|
||||||
}}>
|
</div>
|
||||||
{modName}
|
)
|
||||||
</Typography>
|
|
||||||
<Typography variant="body2" sx={{
|
|
||||||
color: 'rgba(255, 255, 255, 0.7)',
|
|
||||||
lineHeight: 1.6,
|
|
||||||
}}>
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Box sx={{ display: 'flex', gap: 1, mb: 2 }}>
|
|
||||||
<Chip
|
|
||||||
label={`${sameMods.length} versions`}
|
|
||||||
size="small"
|
|
||||||
sx={{
|
|
||||||
backgroundColor: 'rgba(233, 69, 96, 0.2)',
|
|
||||||
color: '#ff6b6b',
|
|
||||||
fontWeight: 600,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{hasBeta && (
|
|
||||||
<Chip
|
|
||||||
label="Beta"
|
|
||||||
size="small"
|
|
||||||
color="warning"
|
|
||||||
sx={{ fontWeight: 600 }}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Divider sx={{ my: 2, borderColor: 'rgba(255, 255, 255, 0.1)' }} />
|
|
||||||
|
|
||||||
<Typography variant="subtitle2" sx={{
|
|
||||||
color: 'rgba(255, 255, 255, 0.9)',
|
|
||||||
fontWeight: 600,
|
|
||||||
mb: 1.5,
|
|
||||||
}}>
|
|
||||||
Main versions:
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
{sameMods.filter(m => !m.isBeta).map(mod => (
|
|
||||||
<VersionLink key={mod.id} to={"/mod/" + mod.id} state={mod.id}>
|
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', width: '100%' }}>
|
|
||||||
<Typography variant="body2" sx={{ fontWeight: 600, color: 'rgba(255, 255, 255, 0.7)' }}>
|
|
||||||
Version {mod.version}
|
|
||||||
</Typography>
|
|
||||||
<Typography variant="caption" sx={{
|
|
||||||
color: 'rgba(255, 255, 255, 0.5)',
|
|
||||||
}}>
|
|
||||||
→
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
</VersionLink>
|
|
||||||
))}
|
|
||||||
|
|
||||||
{hasBeta && (
|
|
||||||
<Box sx={{ mt: 2 }}>
|
|
||||||
<Typography variant="subtitle2" sx={{
|
|
||||||
color: 'rgba(255, 193, 7, 0.9)',
|
|
||||||
fontWeight: 600,
|
|
||||||
mb: 1,
|
|
||||||
}}>
|
|
||||||
Beta versions:
|
|
||||||
</Typography>
|
|
||||||
{betaVersion && (
|
|
||||||
<VersionLink to={"/mod/" + betaVersion.id} state={betaVersion.id}>
|
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', width: '100%' }}>
|
|
||||||
<Typography variant="body2" sx={{ fontWeight: 600 }}>
|
|
||||||
Version {betaVersion.version} (Beta)
|
|
||||||
</Typography>
|
|
||||||
<Typography variant="caption" sx={{ color: 'rgba(255, 255, 255, 0.5)' }}>
|
|
||||||
→
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
</VersionLink>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
</CardContent>
|
|
||||||
|
|
||||||
<CardActions sx={{ px: 3, pb: 3 }}>
|
|
||||||
<Button
|
|
||||||
size="medium"
|
|
||||||
variant="outlined"
|
|
||||||
component={NavLink}
|
|
||||||
to={"/mod/" + latest?.id}
|
|
||||||
state={latest?.id}
|
|
||||||
sx={{
|
|
||||||
width: '100%',
|
|
||||||
color: '#e94560',
|
|
||||||
borderColor: 'rgba(233, 69, 96, 0.5)',
|
|
||||||
fontWeight: 600,
|
|
||||||
borderRadius: '10px',
|
|
||||||
textTransform: 'none',
|
|
||||||
fontSize: '1rem',
|
|
||||||
py: 1.5,
|
|
||||||
'&:hover': {
|
|
||||||
borderColor: '#e94560',
|
|
||||||
backgroundColor: 'rgba(233, 69, 96, 0.1)',
|
|
||||||
transform: 'translateY(-2px)',
|
|
||||||
boxShadow: '0 8px 20px rgba(233, 69, 96, 0.2)',
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Open latest {latest?.version ?? ''}
|
|
||||||
</Button>
|
|
||||||
</CardActions>
|
|
||||||
</ModCard>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<Box>
|
[...mapWithModVersions.keys()].map(m => Mod(m))
|
||||||
|
)
|
||||||
|
|
||||||
<Grid container spacing={3}>
|
|
||||||
{[...new Set(sortedMods.map(m => m.name))].map((modName, index) => (
|
|
||||||
<Grid item xs={12} sm={6} md={4} >
|
|
||||||
{ModCardComponent(modName, index)}
|
|
||||||
</Grid>
|
|
||||||
))}
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ModsPageState {
|
interface ModsPageState {
|
||||||
mods: IMod[];
|
mods: IMod[]
|
||||||
loading: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ModsPage extends React.Component<any, ModsPageState> {
|
class ModsPage extends React.Component<any, ModsPageState> {
|
||||||
@ -274,36 +51,22 @@ class ModsPage extends React.Component<any, ModsPageState> {
|
|||||||
constructor({props}: { props: any }) {
|
constructor({props}: { props: any }) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
mods: [],
|
mods: []
|
||||||
loading: true
|
}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
try {
|
|
||||||
const response = await fetch(AvailableMods);
|
const response = await fetch(AvailableMods);
|
||||||
const data: IMod[] = await response.json();
|
const data: IMod[] = await response.json();
|
||||||
|
console.log(data);
|
||||||
this.setState({
|
this.setState({
|
||||||
mods: data,
|
mods : data
|
||||||
loading: false
|
|
||||||
});
|
});
|
||||||
} catch (error) {
|
|
||||||
console.error('Error loading mods:', error);
|
|
||||||
this.setState({ loading: false });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (this.state.loading) {
|
return <div>{Mods(this.state.mods)}</div>;
|
||||||
return (
|
|
||||||
<Box sx={{ display: 'flex', justifyContent: 'center', py: 8 }}>
|
|
||||||
<LinearProgress sx={{ width: '200px' }} />
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return <Mods mods={this.state.mods} />;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ModsPage;
|
export default ModsPage
|
||||||
@ -8,43 +8,29 @@ import {
|
|||||||
Accordion,
|
Accordion,
|
||||||
AccordionDetails,
|
AccordionDetails,
|
||||||
AccordionSummary,
|
AccordionSummary,
|
||||||
Box,
|
|
||||||
Button,
|
Button,
|
||||||
Container,
|
ButtonGroup,
|
||||||
Divider,
|
Grid2, Link,
|
||||||
Grid2, LinearProgress,
|
|
||||||
Link,
|
|
||||||
List,
|
List,
|
||||||
ListItem,
|
ListItem,
|
||||||
|
ListSubheader,
|
||||||
Paper,
|
Paper,
|
||||||
Typography,
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableContainer,
|
||||||
|
TableHead,
|
||||||
|
TableRow,
|
||||||
|
ToggleButton,
|
||||||
|
ToggleButtonClassKey,
|
||||||
|
ToggleButtonGroup,
|
||||||
|
Typography
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import {ArrowBack, ExpandMore} from "@mui/icons-material";
|
import {ArrowBack, ArrowDropDown, ExpandMore} from "@mui/icons-material";
|
||||||
|
import ArmorType from "../classes/ArmorType";
|
||||||
|
import Weapon from "../classes/Weapon";
|
||||||
import {IRaceUnits, IUnitShort} from "../types/IUnitShort";
|
import {IRaceUnits, IUnitShort} from "../types/IUnitShort";
|
||||||
import {IBuildingShort, IRaceBuildings} from "../types/IBuildingShort";
|
import {IBuildingShort, IRaceBuildings} from "../types/IBuildingShort";
|
||||||
import {styled} from '@mui/material/styles';
|
|
||||||
import {StyledLink} from "../commons/StyledLink";
|
|
||||||
import {BackButton} from "../commons/BackButton";
|
|
||||||
|
|
||||||
const SectionTitle = styled(Typography)(({ theme }) => ({
|
|
||||||
fontWeight: 700,
|
|
||||||
mb: 2,
|
|
||||||
fontSize: '1.25rem',
|
|
||||||
}));
|
|
||||||
|
|
||||||
const UnitCard = styled(Paper)(({ theme }) => ({
|
|
||||||
background: 'rgba(255, 255, 255, 0.03)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.05)',
|
|
||||||
borderRadius: '10px',
|
|
||||||
padding: theme.spacing(1.5, 2),
|
|
||||||
transition: 'all 0.2s ease',
|
|
||||||
'&:hover': {
|
|
||||||
background: 'rgba(233, 69, 96, 0.1)',
|
|
||||||
borderColor: 'rgba(233, 69, 96, 0.3)',
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const BuildingCard = styled(UnitCard)(({ theme }) => ({}));
|
|
||||||
|
|
||||||
interface RacePageState {
|
interface RacePageState {
|
||||||
mod: IMod,
|
mod: IMod,
|
||||||
@ -55,27 +41,13 @@ interface RacePageState {
|
|||||||
|
|
||||||
function Unit(unit: IUnitShort, modId: number, raceId: String) {
|
function Unit(unit: IUnitShort, modId: number, raceId: String) {
|
||||||
|
|
||||||
return (<Link href={"/mod/" + modId + "/race/" + raceId + "/unit/" + unit.id} sx={{
|
return (<Link href={"/mod/" + modId + "/race/" + raceId + "/unit/" + unit.id}><ListItem>
|
||||||
color: 'rgba(255,255,255,0.85)',
|
|
||||||
textDecoration: 'none',
|
|
||||||
display: 'block',
|
|
||||||
'&:hover': { color: '#e94560' }
|
|
||||||
}}>
|
|
||||||
<ListItem sx={{
|
|
||||||
color: 'rgba(255,255,255,0.85)',
|
|
||||||
padding: '6px 12px',
|
|
||||||
background: 'rgba(255,255,255,0.02)',
|
|
||||||
borderRadius: '8px',
|
|
||||||
border: '1px solid rgba(255,255,255,0.05)',
|
|
||||||
transition: 'all 0.2s ease',
|
|
||||||
'&:hover': { background: 'rgba(233, 69, 96, 0.1)', borderColor: 'rgba(233, 69, 96, 0.3)' }
|
|
||||||
}}>
|
|
||||||
{unit.icon && <img className="unitIcon" src={IconUrl + unit.icon.replaceAll('\\', '/')}/>}
|
{unit.icon && <img className="unitIcon" src={IconUrl + unit.icon.replaceAll('\\', '/')}/>}
|
||||||
{unit.name}
|
{unit.name}
|
||||||
{unit.canDetect && <span> <img style={{verticalAlign: "top"}}
|
{unit.canDetect && <span> <img style={{verticalAlign: "top"}}
|
||||||
src="/images/DETECT_YES.webp"/></span>}
|
src="/images/DETECT_YES.webp"/></span>}
|
||||||
</ListItem>
|
|
||||||
</Link>)
|
</ListItem></Link>)
|
||||||
}
|
}
|
||||||
|
|
||||||
function UnitSmall(unit: IUnitShort, modId: number, raceId: String) {
|
function UnitSmall(unit: IUnitShort, modId: number, raceId: String) {
|
||||||
@ -87,33 +59,23 @@ function UnitSmall(unit: IUnitShort, modId: number, raceId: String) {
|
|||||||
unitName = unit.name;
|
unitName = unit.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (<StyledLink href={"/mod/" + modId + "/race/" + raceId + "/unit/" + unit.id} >
|
return (<Link href={"/mod/" + modId + "/race/" + raceId + "/unit/" + unit.id}>
|
||||||
{unit.icon && <img className="unitIconSmall" src={IconUrl + unit.icon.replaceAll('\\', '/')}/>}
|
{unit.icon && <img className="unitIconSmall" src={IconUrl + unit.icon.replaceAll('\\', '/')}/>}
|
||||||
<span style={{fontSize: 14}}>{unitName}</span>
|
<span style={{fontSize: 12}}>{unitName}</span>
|
||||||
{unit.canDetect && <span> <img
|
{unit.canDetect && <span> <img
|
||||||
src="/images/DETECT_YES.webp"/></span>}<br/></StyledLink>)
|
src="/images/DETECT_YES.webp"/></span>}<br/></Link>)
|
||||||
}
|
}
|
||||||
|
|
||||||
function Building(building: IBuildingShort, modId: number, raceId: String) {
|
function Building(building: IBuildingShort, modId: number, raceId: String) {
|
||||||
|
|
||||||
return (<Grid2 size={{xs: 12, md: 3}}>
|
return (<Grid2 size={{xs: 12, md: 3}}><Link href={"/mod/" + modId + "/race/" + raceId + "/building/" + building.id}><ListItem>
|
||||||
<Link href={"/mod/" + modId + "/race/" + raceId + "/building/" + building.id} sx={{
|
|
||||||
textDecoration: 'none',
|
|
||||||
display: 'block',
|
|
||||||
'&:hover': { color: '#e94560' }
|
|
||||||
}}>
|
|
||||||
<BuildingCard elevation={0}>
|
|
||||||
<ListItem sx={{
|
|
||||||
padding: '8px 12px',
|
|
||||||
}}>
|
|
||||||
{building.icon && <img className="unitIcon" src={IconUrl + building.icon.replaceAll('\\', '/')}/>}
|
{building.icon && <img className="unitIcon" src={IconUrl + building.icon.replaceAll('\\', '/')}/>}
|
||||||
<StyledLink>{building.name}</StyledLink>
|
{building.name}
|
||||||
{building.canDetect && <span> <img style={{verticalAlign: "top"}}
|
{building.canDetect && <span> <img style={{verticalAlign: "top"}}
|
||||||
src="/images/DETECT_YES.webp"/></span>}
|
src="/images/DETECT_YES.webp"/></span>}
|
||||||
</ListItem>
|
|
||||||
|
</ListItem></Link>
|
||||||
{building.units.map(unit => UnitSmall(unit, modId, raceId))}
|
{building.units.map(unit => UnitSmall(unit, modId, raceId))}
|
||||||
</BuildingCard>
|
|
||||||
</Link>
|
|
||||||
</Grid2>)
|
</Grid2>)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,61 +127,59 @@ class Units extends React.Component<UnitsProps, UnitsState> {
|
|||||||
document.title = this.state.buildings?.race.name
|
document.title = this.state.buildings?.race.name
|
||||||
}
|
}
|
||||||
|
|
||||||
const accordionSx = {
|
|
||||||
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
||||||
borderRadius: '12px',
|
|
||||||
'&:before': { display: 'none' },
|
|
||||||
'&.Mui-expanded': { margin: '0 0 8px 0' },
|
|
||||||
};
|
|
||||||
|
|
||||||
return (this.state.buildings != null ?
|
return (this.state.buildings != null ?
|
||||||
<Box>
|
<div>
|
||||||
<Grid2 container spacing={2}>
|
<Grid2 container spacing={2}>
|
||||||
{this.state.buildings.buildings.map(building => Building(building, this.props.modId, this.props.raceId))}
|
{this.state.buildings.buildings.map(building => Building(building, this.props.modId, this.props.raceId))}
|
||||||
</Grid2>
|
</Grid2>
|
||||||
{this.state.buildings.buildingsAdvanced.length > 0 && <Box sx={{ mt: 3 }}>
|
{this.state.buildings.buildingsAdvanced.length > 0 && <div><hr/><Grid2 container spacing={2}>
|
||||||
<Divider sx={{ my: 2, borderColor: 'rgba(255, 255, 255, 0.1)' }} />
|
|
||||||
<SectionTitle>Advanced buildings</SectionTitle>
|
|
||||||
<Grid2 container spacing={2}>
|
|
||||||
{this.state.buildings.buildingsAdvanced.map(building => Building(building, this.props.modId, this.props.raceId))}
|
{this.state.buildings.buildingsAdvanced.map(building => Building(building, this.props.modId, this.props.raceId))}
|
||||||
</Grid2><br/></Box>}
|
</Grid2><br/></div>}
|
||||||
<Box sx={{ mt: 3 }}>
|
<Grid2>
|
||||||
<Accordion sx={accordionSx}>
|
<Grid2 size={{xs: 12, md: 12}}>
|
||||||
|
<Accordion>
|
||||||
<AccordionSummary
|
<AccordionSummary
|
||||||
expandIcon={<ExpandMore sx={{color: '#ffffff'}}/>}
|
expandIcon={<ExpandMore/>}
|
||||||
aria-controls="units-accordion"
|
aria-controls="units-accordion"
|
||||||
id="units-accordion"
|
id="units-accordion"
|
||||||
sx={{color: '#ffffff'}}
|
|
||||||
>
|
>
|
||||||
<SectionTitle sx={{ mb: 0 }}>All units</SectionTitle>
|
<h3>All units</h3>
|
||||||
</AccordionSummary>
|
</AccordionSummary>
|
||||||
<AccordionDetails>
|
<AccordionDetails>
|
||||||
<Grid2 container spacing={2}>
|
<Grid2 container spacing={2}>
|
||||||
<Grid2 size={{xs: 12, md: 4}}>
|
<Grid2 size={{xs: 12, md: 4}}>
|
||||||
<Typography variant="h6" sx={{ color: '#ffffff', fontWeight: 600, mb: 2 }}>Infantry</Typography>
|
<h3>Infantry</h3>
|
||||||
{this.state.units.infantry.map(unit => Unit(unit, this.props.modId, this.props.raceId))}
|
{this.state.units.infantry.map(unit => Unit(unit, this.props.modId, this.props.raceId))}
|
||||||
</Grid2>
|
</Grid2>
|
||||||
<Grid2 size={{xs: 12, md: 4}}>
|
<Grid2 size={{xs: 12, md: 4}}>
|
||||||
<Typography variant="h6" sx={{ color: '#ffffff', fontWeight: 600, mb: 2 }}>Tech</Typography>
|
<h3>Tech</h3>
|
||||||
<List>
|
<List sx={{
|
||||||
|
width: '100%',
|
||||||
|
maxWidth: 360,
|
||||||
|
bgcolor: 'background.paper'
|
||||||
|
}}>
|
||||||
{this.state.units.tech.map(unit => Unit(unit, this.props.modId, this.props.raceId))}
|
{this.state.units.tech.map(unit => Unit(unit, this.props.modId, this.props.raceId))}
|
||||||
</List>
|
</List>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
<Grid2 size={{xs: 12, md: 4}}>
|
<Grid2 size={{xs: 12, md: 4}}>
|
||||||
<Typography variant="h6" sx={{ color: '#ffffff', fontWeight: 600, mb: 2 }}>Support</Typography>
|
<h3>Support</h3>
|
||||||
<List>
|
<List sx={{
|
||||||
|
width: '100%',
|
||||||
|
maxWidth: 360,
|
||||||
|
bgcolor: 'background.paper'
|
||||||
|
}}>
|
||||||
{this.state.units.support.map(unit => Unit(unit, this.props.modId, this.props.raceId))}
|
{this.state.units.support.map(unit => Unit(unit, this.props.modId, this.props.raceId))}
|
||||||
</List>
|
</List>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
</AccordionDetails>
|
</AccordionDetails>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
</Box>
|
</Grid2><br/>
|
||||||
</Box> : <Box sx={{ color: 'rgba(255, 255, 255, 0.5)' }}>Loading</Box>
|
</Grid2>
|
||||||
|
</div> : "Loading"
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
return <Box sx={{ color: 'rgba(255, 255, 255, 0.5)' }}>Loading...</Box>;
|
return "Loading...";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -228,6 +188,7 @@ class RacePageFast extends React.Component<any, RacePageState> {
|
|||||||
|
|
||||||
constructor(props: any) {
|
constructor(props: any) {
|
||||||
super(props);
|
super(props);
|
||||||
|
console.log(this.props.match.params.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -253,43 +214,13 @@ class RacePageFast extends React.Component<any, RacePageState> {
|
|||||||
if (this.state != null && this.state.mod != null && this.state.race != null) {
|
if (this.state != null && this.state.mod != null && this.state.race != null) {
|
||||||
const backRef = "/mod/" + this.state.mod.id
|
const backRef = "/mod/" + this.state.mod.id
|
||||||
|
|
||||||
return (
|
return <div><Link href={backRef}><Button id="back-button" variant="contained"
|
||||||
<Container maxWidth="lg" sx={{ py: 4 }}>
|
startIcon={<ArrowBack/>}> Back</Button></Link>
|
||||||
<BackButton
|
<h1>{this.state.mod.name} ({this.state.mod.version}) - {this.state.race.name}</h1>
|
||||||
variant="outlined"
|
|
||||||
startIcon={<ArrowBack/>}
|
|
||||||
href={backRef}
|
|
||||||
>
|
|
||||||
Back to mod
|
|
||||||
</BackButton>
|
|
||||||
|
|
||||||
<Box sx={{ mb: 4 }}>
|
|
||||||
<Typography variant="h3" component="h1" sx={{
|
|
||||||
fontWeight: 800,
|
|
||||||
mb: 1,
|
|
||||||
background: 'linear-gradient(135deg, #ffffff 0%, #e0e0e0 100%)',
|
|
||||||
WebkitBackgroundClip: 'text',
|
|
||||||
WebkitTextFillColor: 'transparent',
|
|
||||||
}}>
|
|
||||||
{this.state.race.name}
|
|
||||||
</Typography>
|
|
||||||
<Typography variant="h6" sx={{
|
|
||||||
color: 'rgba(255, 255, 255, 0.6)',
|
|
||||||
fontWeight: 500,
|
|
||||||
}}>
|
|
||||||
{this.state.mod.name} ({this.state.mod.version})
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Units raceId={this.state.race.id} modId={this.state.mod.id}/>
|
<Units raceId={this.state.race.id} modId={this.state.mod.id}/>
|
||||||
</Container>
|
</div>;
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
return (
|
return "loading...";
|
||||||
<Container maxWidth="lg" sx={{ py: 4 }}>
|
|
||||||
<LinearProgress sx={{ width: '200px', mx: 'auto', display: 'block' }} />
|
|
||||||
</Container>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,18 +7,15 @@ import {
|
|||||||
Accordion,
|
Accordion,
|
||||||
AccordionDetails,
|
AccordionDetails,
|
||||||
AccordionSummary,
|
AccordionSummary,
|
||||||
Box,
|
|
||||||
Button,
|
Button,
|
||||||
Container,
|
Grid2,
|
||||||
Divider,
|
|
||||||
Grid2, LinearProgress,
|
|
||||||
Paper,
|
Paper,
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
TableCell,
|
TableCell,
|
||||||
|
TableContainer,
|
||||||
TableRow,
|
TableRow,
|
||||||
Tooltip,
|
Tooltip
|
||||||
Typography,
|
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import {ArrowBack, ExpandMore} from "@mui/icons-material";
|
import {ArrowBack, ExpandMore} from "@mui/icons-material";
|
||||||
import ArmorType from "../classes/ArmorType";
|
import ArmorType from "../classes/ArmorType";
|
||||||
@ -33,30 +30,6 @@ import {renderAffectedResearches} from "../classes/building/Research";
|
|||||||
import {ModifiersProvidesTable} from "../classes/ModifiersProvideTable";
|
import {ModifiersProvidesTable} from "../classes/ModifiersProvideTable";
|
||||||
import Ability from "../classes/Ability";
|
import Ability from "../classes/Ability";
|
||||||
import DeathExplosion from "../classes/DeathExplosion";
|
import DeathExplosion from "../classes/DeathExplosion";
|
||||||
import {styled} from '@mui/material/styles';
|
|
||||||
import {DescriptionBox} from "../commons/DescriptionBox";
|
|
||||||
import {BackButton} from "../commons/BackButton";
|
|
||||||
|
|
||||||
const SectionTitle = styled(Typography)(({ theme }) => ({
|
|
||||||
fontWeight: 700,
|
|
||||||
mb: 2,
|
|
||||||
fontSize: '1.25rem',
|
|
||||||
}));
|
|
||||||
|
|
||||||
const StatsPaper = styled(Paper)(({ theme }) => ({
|
|
||||||
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
||||||
borderRadius: '12px',
|
|
||||||
overflow: 'hidden',
|
|
||||||
'& .MuiTableBody .MuiTableRow-root': {
|
|
||||||
'&:last-child td, &:last-child th': { border: 0 },
|
|
||||||
},
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-head': {
|
|
||||||
color: '#e94560',
|
|
||||||
fontWeight: 600,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
interface UintPageState {
|
interface UintPageState {
|
||||||
unit: IUnit,
|
unit: IUnit,
|
||||||
@ -66,7 +39,7 @@ interface UintPageState {
|
|||||||
|
|
||||||
function Unit(unit: IUnit, mod: IMod) {
|
function Unit(unit: IUnit, mod: IMod) {
|
||||||
|
|
||||||
document.title = unit.name + " — " + mod.name
|
document.title = unit.name
|
||||||
|
|
||||||
const morale = (unit.moraleMax !== null) ? <span>
|
const morale = (unit.moraleMax !== null) ? <span>
|
||||||
<img style={{verticalAlign: "top"}} src="/images/ARM_Morale.webp"/> {unit.moraleMax}
|
<img style={{verticalAlign: "top"}} src="/images/ARM_Morale.webp"/> {unit.moraleMax}
|
||||||
@ -98,7 +71,7 @@ function Unit(unit: IUnit, mod: IMod) {
|
|||||||
const SergeantShort = (props: sergeantProps) => {
|
const SergeantShort = (props: sergeantProps) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span style={{fontSize: 20, color: '#ffffff'}}>
|
<span style={{fontSize: 20}}>
|
||||||
{props.icon && <img className="sergeantIcon" src={IconUrl + props.icon.replaceAll('\\', '/')}/> }
|
{props.icon && <img className="sergeantIcon" src={IconUrl + props.icon.replaceAll('\\', '/')}/> }
|
||||||
{props.name}
|
{props.name}
|
||||||
{props.canDetect && <span> <img style={{verticalAlign: "top"}}
|
{props.canDetect && <span> <img style={{verticalAlign: "top"}}
|
||||||
@ -109,35 +82,21 @@ function Unit(unit: IUnit, mod: IMod) {
|
|||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<div>
|
||||||
<Box sx={{ mb: 3 }}>
|
<h1>{mod.name} ({mod.version})</h1>
|
||||||
<Typography variant="h4" component="h2" sx={{
|
<h2>{unit.icon &&
|
||||||
fontWeight: 800,
|
<img className="unitIcon" src={IconUrl + unit.icon.replaceAll('\\', '/')}/>} {unit.name} </h2>
|
||||||
mb: 1,
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: 2,
|
|
||||||
}}>
|
|
||||||
{unit.icon &&
|
|
||||||
<img className="unitIcon" src={IconUrl + unit.icon.replaceAll('\\', '/')}/>}
|
|
||||||
{unit.name}
|
|
||||||
</Typography>
|
|
||||||
<Typography variant="subtitle1" sx={{
|
|
||||||
color: 'rgba(255, 255, 255, 0.6)',
|
|
||||||
fontWeight: 500,
|
|
||||||
}}>
|
|
||||||
{mod.name} ({mod.version})
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Grid2 container spacing={3}>
|
<Grid2 container spacing={2}>
|
||||||
<Grid2 size={{xs: 12, md: 4}}>
|
<Grid2 size={{xs: 12, md: 4}}>
|
||||||
<StatsPaper >
|
<TableContainer component={Paper}>
|
||||||
<Table size="small" aria-label="a dense table">
|
<Table size="small" aria-label="a dense table">
|
||||||
<TableBody id="unit-stats-table">
|
<TableBody id="unit-stats-table">
|
||||||
<TableRow>
|
<TableRow
|
||||||
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
|
>
|
||||||
<TableCell component="th" scope="row">Cost</TableCell>
|
<TableCell component="th" scope="row">Cost</TableCell>
|
||||||
<TableCell>
|
<TableCell component="th" scope="row">
|
||||||
{unit.buildCostRequisition > 0 &&
|
{unit.buildCostRequisition > 0 &&
|
||||||
<span> <img style={{verticalAlign: "top"}}
|
<span> <img style={{verticalAlign: "top"}}
|
||||||
src="/images/Resource_requisition.gif"/>
|
src="/images/Resource_requisition.gif"/>
|
||||||
@ -223,18 +182,24 @@ function Unit(unit: IUnit, mod: IMod) {
|
|||||||
{unit.squadMaxSize > 1 &&
|
{unit.squadMaxSize > 1 &&
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell>Squad size</TableCell>
|
<TableCell>Squad size</TableCell>
|
||||||
<TableCell>{unit.squadStartSize} / {unit.squadMaxSize}</TableCell>
|
<TableCell>
|
||||||
|
{unit.squadStartSize} / {unit.squadMaxSize}
|
||||||
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
}
|
}
|
||||||
<TableRow>
|
<TableRow
|
||||||
<TableCell >Armor type</TableCell>
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
<TableCell>
|
>
|
||||||
|
<TableCell component="th" scope="row">Armor type</TableCell>
|
||||||
|
<TableCell component="th" scope="row">
|
||||||
{unit.armorType2 == null ? <ArmorType name={unit.armorType.name} compact={false}/> : <Tooltip title={"upgrade/debuff can turns to " + unit.armorType2.name}><span><ArmorType name={unit.armorType.name} compact={false}/></span></Tooltip> }
|
{unit.armorType2 == null ? <ArmorType name={unit.armorType.name} compact={false}/> : <Tooltip title={"upgrade/debuff can turns to " + unit.armorType2.name}><span><ArmorType name={unit.armorType.name} compact={false}/></span></Tooltip> }
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow
|
||||||
<TableCell >Health</TableCell>
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
<TableCell>
|
>
|
||||||
|
<TableCell component="th" scope="row">Health</TableCell>
|
||||||
|
<TableCell component="th" scope="row">
|
||||||
<img style={{verticalAlign: "top"}}
|
<img style={{verticalAlign: "top"}}
|
||||||
src="/images/Health_icon.webp"/>
|
src="/images/Health_icon.webp"/>
|
||||||
{unit.health} {unit.healthRegeneration > 0 &&
|
{unit.health} {unit.healthRegeneration > 0 &&
|
||||||
@ -242,54 +207,78 @@ function Unit(unit: IUnit, mod: IMod) {
|
|||||||
{unit.armour !== undefined && unit.armour !== 0 && <span><img style={{height: 20, verticalAlign: "top"}} src="/images/defence.png"/>{unit.armour} </span> }
|
{unit.armour !== undefined && unit.armour !== 0 && <span><img style={{height: 20, verticalAlign: "top"}} src="/images/defence.png"/>{unit.armour} </span> }
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow
|
||||||
<TableCell >Move speed</TableCell>
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
<TableCell>{unit.moveSpeed}</TableCell>
|
>
|
||||||
|
<TableCell component="th" scope="row">Move speed</TableCell>
|
||||||
|
<TableCell component="th" scope="row">
|
||||||
|
{unit.moveSpeed}
|
||||||
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow
|
||||||
<TableCell >Morale</TableCell>
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
<TableCell>{morale}</TableCell>
|
>
|
||||||
|
<TableCell component="th" scope="row">Morale</TableCell>
|
||||||
|
<TableCell component="th" scope="row">
|
||||||
|
{morale}
|
||||||
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow
|
||||||
<TableCell >Mass</TableCell>
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
<TableCell>{unit.mass}</TableCell>
|
>
|
||||||
|
<TableCell component="th" scope="row">Mass</TableCell>
|
||||||
|
<TableCell component="th" scope="row">
|
||||||
|
{unit.mass}
|
||||||
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
<TableRow
|
||||||
<TableCell >Vision</TableCell>
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
<TableCell><Vision sight={unit.sightRadius} detect={unit.detectRadius}/></TableCell>
|
>
|
||||||
|
<TableCell component="th" scope="row">Vision</TableCell>
|
||||||
|
<TableCell component="th" scope="row">
|
||||||
|
<Vision sight={unit.sightRadius} detect={unit.detectRadius}/>
|
||||||
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
{unit.repairMax !== undefined && unit.repairMax !== null &&
|
{unit.repairMax !== undefined && unit.repairMax !== null &&
|
||||||
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
<TableRow>
|
||||||
<TableCell>Repair max</TableCell>
|
<TableCell>Repair max</TableCell>
|
||||||
<TableCell>{unit.repairMax}</TableCell>
|
<TableCell>
|
||||||
|
{unit.repairMax}
|
||||||
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
}
|
}
|
||||||
{unit.repairSpeed !== undefined && unit.repairSpeed !== null && unit.repairCostPercent !== null &&
|
{unit.repairSpeed !== undefined && unit.repairSpeed !== null && unit.repairCostPercent !== null &&
|
||||||
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
<TableRow>
|
||||||
<TableCell>Repair</TableCell>
|
<TableCell>Repair</TableCell>
|
||||||
<TableCell>{unit.repairSpeed} hp/s; {unit.repairCostPercent}% cost</TableCell>
|
<TableCell>
|
||||||
|
{unit.repairSpeed} hp/s; {unit.repairCostPercent}% cost
|
||||||
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
}
|
}
|
||||||
{unit.mobValue != null &&
|
{unit.mobValue != null &&
|
||||||
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
<TableRow>
|
||||||
<TableCell>Mob value</TableCell>
|
<TableCell>Mob value</TableCell>
|
||||||
<TableCell><span> <img style={{height: 20, verticalAlign: "top"}} src="/images/Mob_bonus.gif"/> {unit.mobValue} </span></TableCell>
|
<TableCell>
|
||||||
|
<span> <img style={{height: 20, verticalAlign: "top"}} src="/images/Mob_bonus.gif"/> {unit.mobValue} </span>
|
||||||
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
}
|
}
|
||||||
{unit.squadLimit !== undefined && unit.squadLimit !== null &&
|
{unit.squadLimit !== undefined && unit.squadLimit !== null &&
|
||||||
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
<TableRow>
|
||||||
<TableCell>Limit</TableCell>
|
<TableCell>Limit</TableCell>
|
||||||
<TableCell>{unit.squadLimit}</TableCell>
|
<TableCell>
|
||||||
|
{unit.squadLimit}
|
||||||
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
}
|
}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</StatsPaper>
|
</TableContainer>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
<Grid2 size={{xs: 12, md: 8}}>
|
<Grid2 size={8}>
|
||||||
<DescriptionBox>
|
<div style={{whiteSpace: "pre-wrap"}}>
|
||||||
{unit.description}
|
{unit.description}
|
||||||
</DescriptionBox>
|
</div>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
{unit.requirements !== null &&
|
{unit.requirements !== null &&
|
||||||
<Grid2 size={{xs: 12, md: 12}}>
|
<Grid2 size={{xs: 12, md: 12}}>
|
||||||
@ -297,21 +286,19 @@ function Unit(unit: IUnit, mod: IMod) {
|
|||||||
</Grid2>}
|
</Grid2>}
|
||||||
<Grid2 size={12}>
|
<Grid2 size={12}>
|
||||||
{unit.sergeants.map(s =>
|
{unit.sergeants.map(s =>
|
||||||
<Accordion key={s.id} sx={{
|
<Accordion key={s.id}>
|
||||||
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
||||||
borderRadius: '12px',
|
|
||||||
mb: 1,
|
|
||||||
'&:before': { display: 'none' },
|
|
||||||
'&.Mui-expanded': { margin: '0 0 8px 0' },
|
|
||||||
}}>
|
|
||||||
<AccordionSummary
|
<AccordionSummary
|
||||||
sx={{color: '#ffffff'}}>
|
expandIcon={<ExpandMore/>}
|
||||||
|
aria-controls="panel1-content"
|
||||||
|
id="panel1-header"
|
||||||
|
>
|
||||||
<SergeantShort name={s.name} icon={s.icon} canDetect={s.detectRadius > 0}/>
|
<SergeantShort name={s.name} icon={s.icon} canDetect={s.detectRadius > 0}/>
|
||||||
</AccordionSummary>
|
</AccordionSummary>
|
||||||
<AccordionDetails sx={{color: 'rgba(255, 255, 255, 0.85)'}}>
|
<AccordionDetails>
|
||||||
<Sergeant mod={mod} sergeant={s} race={unit.race}/>
|
<Sergeant mod={mod} sergeant={s} race={unit.race}/>
|
||||||
|
<hr/>
|
||||||
</AccordionDetails>
|
</AccordionDetails>
|
||||||
|
|
||||||
</Accordion>)}
|
</Accordion>)}
|
||||||
</Grid2>
|
</Grid2>
|
||||||
|
|
||||||
@ -319,17 +306,17 @@ function Unit(unit: IUnit, mod: IMod) {
|
|||||||
unit.moraleBrakeModifiers.find(m => m.reference.includes("speed_maximum_modifier") && m.value === 1.2) !== undefined &&
|
unit.moraleBrakeModifiers.find(m => m.reference.includes("speed_maximum_modifier") && m.value === 1.2) !== undefined &&
|
||||||
unit.moraleBrakeModifiers.length === 2)
|
unit.moraleBrakeModifiers.length === 2)
|
||||||
&& <Grid2 size={12}>
|
&& <Grid2 size={12}>
|
||||||
<SectionTitle><img style={{verticalAlign: "top"}} src="/images/ARM_Morale.webp"/> Morale broken unusual behavior <img style={{verticalAlign: "top"}} src="/images/ARM_Morale.webp"/></SectionTitle>
|
<h3><img style={{verticalAlign: "top"}} src="/images/ARM_Morale.webp"/> Morale broken unusual behavior <img style={{verticalAlign: "top"}} src="/images/ARM_Morale.webp"/></h3>
|
||||||
<ModifiersProvidesTable modifiers={unit.moraleBrakeModifiers} modId={unit.modId} race={unit.race} affectedData={unit.affectedData}/>
|
<ModifiersProvidesTable modifiers={unit.moraleBrakeModifiers} modId={unit.modId} race={unit.race} affectedData={unit.affectedData}/>
|
||||||
</Grid2>}
|
</Grid2>}
|
||||||
|
|
||||||
{unit.modifiers.length > 0 && <Grid2 size={12}>
|
{unit.modifiers.length > 0 && <Grid2 size={12}>
|
||||||
<SectionTitle>Affected on</SectionTitle>
|
<h3>Affected on</h3>
|
||||||
<ModifiersProvidesTable modifiers={unit.modifiers} modId={unit.modId} race={unit.race} affectedData={unit.affectedData}/>
|
<ModifiersProvidesTable modifiers={unit.modifiers} modId={unit.modId} race={unit.race} affectedData={unit.affectedData}/>
|
||||||
</Grid2>}
|
</Grid2>}
|
||||||
|
|
||||||
{unit.abilities.length > 0 && <Grid2 size={12}>
|
{unit.abilities.length > 0 && <Grid2 size={12}>
|
||||||
<SectionTitle>Abilities</SectionTitle>
|
<h3>Abilities</h3>
|
||||||
{unit.abilities.map(a =>
|
{unit.abilities.map(a =>
|
||||||
<Ability mod={mod} ability={a} race={unit.race}/>
|
<Ability mod={mod} ability={a} race={unit.race}/>
|
||||||
)}
|
)}
|
||||||
@ -351,14 +338,10 @@ function Unit(unit: IUnit, mod: IMod) {
|
|||||||
{renderAffectedResearches(unit.affectedResearches, mod.id, unit.race.id)}
|
{renderAffectedResearches(unit.affectedResearches, mod.id, unit.race.id)}
|
||||||
</Grid2>
|
</Grid2>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
|
<b className="hotkey">Hotkey: {unit.hotkey}</b>
|
||||||
<Box sx={{ mt: 3, mb: 2, fontWeight: 600, fontSize: '0.85rem' }}>
|
<hr/>
|
||||||
Hotkey: {unit.hotkey}
|
|
||||||
</Box>
|
|
||||||
<Divider sx={{ my: 3, borderColor: 'rgba(255, 255, 255, 0.1)' }} />
|
|
||||||
<UnitsTable modId={mod.id}/>
|
<UnitsTable modId={mod.id}/>
|
||||||
</Box>
|
</div>)
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -388,24 +371,12 @@ class UnitPage extends React.Component<any, UintPageState> {
|
|||||||
if (this.state != null && this.state.unit != null && this.state.mod != null) {
|
if (this.state != null && this.state.unit != null && this.state.mod != null) {
|
||||||
const backRef = "/mod/" + this.props.match.params.modId + "/race/" + this.props.match.params.raceId
|
const backRef = "/mod/" + this.props.match.params.modId + "/race/" + this.props.match.params.raceId
|
||||||
|
|
||||||
return (
|
return <div key={this.state.unit.id}><a href={backRef}><Button id="back-button" variant="contained"
|
||||||
<Container maxWidth="lg" sx={{ py: 4 }}>
|
startIcon={<ArrowBack/>}> Back</Button></a>
|
||||||
<BackButton
|
|
||||||
variant="outlined"
|
|
||||||
startIcon={<ArrowBack/>}
|
|
||||||
href={backRef}
|
|
||||||
>
|
|
||||||
Back to race
|
|
||||||
</BackButton>
|
|
||||||
{Unit(this.state.unit, this.state.mod)}
|
{Unit(this.state.unit, this.state.mod)}
|
||||||
</Container>
|
</div>;
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
return (
|
return <div key = {'loading'}>loading...</div>;
|
||||||
<Box sx={{ display: 'flex', justifyContent: 'center', py: 8 }}>
|
|
||||||
<LinearProgress sx={{ width: '200px' }} />
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
export interface IMod {
|
export interface IMod {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
order: number;
|
|
||||||
version: string;
|
version: string;
|
||||||
technicalName: string;
|
technicalName: string;
|
||||||
isBeta: boolean;
|
isBeta: boolean;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user