Global update

- add requirements for units, sergeants, buildings and weapons
- add uiIndexHint for units, buildings, researches and addons
- add addon affects
- improve campaign entities clear
- add dds converter definitive edition
- add all files lowercase function before mod parse
- add addon modifiers info
- add advanced build menu grid
- add title according building/unit/mod/race
This commit is contained in:
Anibus 2025-10-11 01:34:18 +03:00
parent 851bb71601
commit f0fde93d7b
20 changed files with 216 additions and 224 deletions

BIN
public/images/shakal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -7,7 +7,7 @@
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<meta <meta
name="description" name="description"
content="Web site created using create-react-app" content="The word 'Caldiris' is slang for someone who drinks alcohol in large quantities. For example, the phrase 'he was caldiris all night' implies that the person drank heavily throughout the night and posted content on dawn-of-war-unification-mod.fandom.com."
/> />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!-- <!--

View File

@ -1,16 +1,6 @@
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,
Button,
Container,
createTheme,
Grid2,
IconButton,
ThemeProvider,
Toolbar,
Typography
} from "@mui/material";
import {MyRoutes} from "./Routes"; import {MyRoutes} from "./Routes";
function App() { function App() {
@ -43,11 +33,11 @@ function App() {
> >
</IconButton> </IconButton>
<Typography variant="h6" component="div" sx={{flexGrow: 1}}> <Typography variant="h6" component="div" sx={{flexGrow: 1}}>
Autogeneration wiki (by Anibus) Autogeneration wiki
</Typography> </Typography>
<Button color="inherit" onClick={steamLogin}> {/*<Button color="inherit" onClick={steamLogin}>
Log in through Steam Log in through Steam
</Button> </Button>*/}
</Toolbar> </Toolbar>
</AppBar> </AppBar>
<Container> <Container>

View File

@ -2,8 +2,9 @@ import {Paper, Table, TableCell, TableContainer, TableRow} from "@mui/material";
import React from "react"; import React from "react";
import {IModifier} from "../types/IModifier"; import {IModifier} from "../types/IModifier";
import {IconUrl} from "../core/api"; import {IconUrl} from "../core/api";
import {IResearch} from "../types/IResearch";
import {Irace} from "../types/Irace"; import {Irace} from "../types/Irace";
import {IAffectedData} from "../types/IAffectedData";
import {IMod} from "../types/Imod";
interface IModifiersProvidesTable{ interface IModifiersProvidesTable{
modifiers: IModifier[], modifiers: IModifier[],
@ -11,7 +12,8 @@ interface IModifiersProvidesTable{
interface IModifiersProvidesResearchTable{ interface IModifiersProvidesResearchTable{
modifiers: IModifier[], modifiers: IModifier[],
research: IResearch, affectedData: IAffectedData,
mod: IMod,
race: Irace, race: Irace,
} }
@ -130,43 +132,43 @@ export function ModifiersProvidesAddonTable (props: IModifiersProvidesTable) {
) )
} }
export function ModifiersProvidesResearchTable (props: IModifiersProvidesResearchTable) { export function ModifiersProvidesTable (props: IModifiersProvidesResearchTable) {
let mods = props.modifiers let mods = props.modifiers
function getTarget(target: String, research: IResearch, race: Irace) { function getTarget(target: String) {
console.log(research.affectedUnits.map(au => au.filename)) console.log(props.affectedData.affectedUnits.map(au => au.filename))
var affectedUnit = research.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)}/><a src={getIcon(affectedUnit.icon)}/><a
href={`/mod/${research.modId}/race/${race.id}/unit/${affectedUnit.id}`}> href={`/mod/${props.mod.id}/race/${props.race.id}/unit/${affectedUnit.id}`}>
{affectedUnit.name} {affectedUnit.name}
</a></span> </a></span>
} }
var affectedSergeant = research.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 style={{verticalAlign: "top", height: 25}} src={getIcon(affectedSergeant.icon)}/>{affectedSergeant.name} at <img style={{verticalAlign: "top", height: 25}}
src={getIcon(affectedSergeant.unit.icon)}/><a src={getIcon(affectedSergeant.unit.icon)}/><a
href={`/mod/${research.modId}/race/${race.id}/unit/${affectedSergeant.unit.id}`}> href={`/mod/${props.mod.id}/race/${props.race.id}/unit/${affectedSergeant.unit.id}`}>
{affectedSergeant.unit.name} {affectedSergeant.unit.name}
</a></span> </a></span>
} }
var affectedBuilding = research.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)}/><a return <span><img style={{verticalAlign: "top", height: 25}} src={getIcon(affectedBuilding.icon)}/><a
href={`/mod/${research.modId}/race/${race.id}/building/${affectedBuilding.id}`}> href={`/mod/${props.mod.id}/race/${props.race.id}/building/${affectedBuilding.id}`}>
{affectedBuilding.name} {affectedBuilding.name}
</a> </span> </a> </span>
} }
var affectedWeapon = research.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><img style={{verticalAlign: "top", height: 25}} src={getIcon(unit.icon)}/><a <span><img style={{verticalAlign: "top", height: 25}} src={getIcon(unit.icon)}/><a
href={`/mod/${research.modId}/race/${race.id}/unit/${unit.id}`}> href={`/mod/${props.mod.id}/race/${props.race.id}/unit/${unit.id}`}>
{unit.name} {unit.name}
</a> </span> </a> </span>
) )
@ -177,7 +179,7 @@ export function ModifiersProvidesResearchTable (props: IModifiersProvidesResearc
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)}/><a src={getIcon(affectedSergeant.unit.icon)}/><a
href={`/mod/${research.modId}/race/${race.id}/unit/${affectedSergeant.unit.id}`}> href={`/mod//${props.mod.id}/race/${props.race.id}/unit/${affectedSergeant.unit.id}`}>
{affectedSergeant.unit.name} {affectedSergeant.unit.name}
</a> </span> </a> </span>
) )
@ -185,7 +187,7 @@ export function ModifiersProvidesResearchTable (props: IModifiersProvidesResearc
{ {
affectedWeapon.buildings.map(affectedBuilding => affectedWeapon.buildings.map(affectedBuilding =>
<span><img style={{verticalAlign: "top", height: 25}} src={getIcon(affectedBuilding.icon)}/><a <span><img style={{verticalAlign: "top", height: 25}} src={getIcon(affectedBuilding.icon)}/><a
href={`/mod/${research.modId}/race/${race.id}/building/${affectedBuilding.id}`}> href={`/mod//${props.mod.id}/race/${props.race.id}/building/${affectedBuilding.id}`}>
{affectedBuilding.name} {affectedBuilding.name}
</a> </span> </a> </span>
) )
@ -194,7 +196,7 @@ export function ModifiersProvidesResearchTable (props: IModifiersProvidesResearc
} }
return <span>Unknown target <i>{target}</i></span>; return <span><i>{target}</i></span>;
} }
return ( return (
@ -204,7 +206,7 @@ export function ModifiersProvidesResearchTable (props: IModifiersProvidesResearc
<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">{getTarget(m.target, props.research, props.race)}</TableCell> <TableCell component="th" scope="row">{getTarget(m.target)}</TableCell>
<TableCell style={{minWidth: 120}} component="th" scope="row">{getModName(m.reference)}</TableCell> <TableCell style={{minWidth: 120}} component="th" scope="row">{getModName(m.reference)}</TableCell>
<TableCell component="th" scope="row">{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>

View File

@ -1,58 +1,74 @@
import {Paper, Table, TableCell, TableContainer, TableRow} from "@mui/material";
import React from "react"; import React from "react";
import {IModifier} from "../types/IModifier";
import {IBuildingShort} from "../types/IBuildingShort"; import {IBuildingShort} from "../types/IBuildingShort";
import {IBuilding, IBuildingAddonShort} from "../types/IBuilding"; import {IBuildingAddonShort} from "../types/IBuilding";
import {IconUrl} from "../core/api"; import {IconUrl} from "../core/api";
import {IResearchRequirements} from "../types/IResearchRequirements"; import {IResearchRequirements} from "../types/IResearchRequirements";
import {goToAddon} from "../pages/BuildingPage"; import {IRequirement, IRequirementLimitByBuildingDto} from "../types/IRequirement";
import {IRequirement} from "../types/IRequirement";
interface IRequiredProps{ interface IRequiredProps{
requirement: IRequirement, requirement: IRequirement,
building: IBuilding, raceId: String,
modId: number,
} }
function Required (props: IRequiredProps) { function Required (props: IRequiredProps) {
function renderRequirementGlobalAddons(rgas: IBuildingAddonShort[], building: IBuilding, modId: number) { function renderRequirementGlobalAddons(rgas: IBuildingAddonShort[],) {
return <div> {rgas.map(rga => return <div> {rgas.map(rga =>
<span>&nbsp; Global addon: <img style={{verticalAlign: "top", height: 25}} <span>&nbsp; Global addon: <img style={{verticalAlign: "top", height: 25}}
src={getIcon(rga.icon)}/> src={getIcon(rga.icon)}/>
&nbsp;<a href={`/mod/${modId}/race/${building.race.id}/building/${rga.buildingId}#addon-${rga.id}`}> &nbsp;<a href={`/mod/${props.modId}/race/${props.raceId}/building/${rga.buildingId}#addon-${rga.id}`}>
{rga.name} {rga.name}
</a></span> </a></span>
)}</div> )}</div>
} }
function renderRequirementBuilding(requirementBuildings: IBuildingShort[], building: IBuilding, modId: number) { function renderRequirementBuilding(requirementBuildings: IBuildingShort[],) {
return requirementBuildings.length > 0 && ( return requirementBuildings.length > 0 && (
<div>&nbsp; Buildings: <img style={{verticalAlign: "top", height: 25}} <div>&nbsp; Buildings: <img style={{verticalAlign: "top", height: 25}}
src={IconUrl + requirementBuildings[0].icon.replaceAll('\\', '/')}/> src={IconUrl + requirementBuildings[0].icon.replaceAll('\\', '/')}/>
&nbsp;{" "}<a href={`/mod/${modId}/race/${building.race.id}/building/${requirementBuildings[0].id}`}> &nbsp;{" "}<a href={`/mod/${props.modId}/race/${props.raceId}/building/${requirementBuildings[0].id}`}>
{requirementBuildings[0].name} {requirementBuildings[0].name}
</a> {requirementBuildings[1] !== undefined && <span>or &nbsp;<img style={{verticalAlign: "top", height: 25}} </a> {requirementBuildings[1] !== undefined && <span>or &nbsp;<img style={{verticalAlign: "top", height: 25}}
src={IconUrl + requirementBuildings[1].icon.replaceAll('\\', '/')}/> src={IconUrl + requirementBuildings[1].icon.replaceAll('\\', '/')}/>
&nbsp;{" "}<a href={`/mod/${modId}/race/${building.race.id}/building/${requirementBuildings[1].id}`}> &nbsp;{" "}<a href={`/mod/${props.modId}/race/${props.raceId}/building/${requirementBuildings[1].id}`}>
{requirementBuildings[1].name}</a></span> } </div> {requirementBuildings[1].name}</a></span> } </div>
); );
} }
function renderRequirementResearches(requirementResearches: IResearchRequirements[], modId: number, raceId: string) { function renderRequirementOwnership(requirementOwnership: string[],) {
return requirementOwnership.length > 0 && <span>&nbsp; Owner: {requirementOwnership.map(o => {
switch(o) {
case 'relic_struct':
return "Relic point ";
default:
return o;
}
}
)} </span>
}
function renderLimitPerBuilding(limitPerBuilding: IRequirementLimitByBuildingDto,) {
return <span>&nbsp; One <img style={{verticalAlign: "top", height: 25}}
src={IconUrl + limitPerBuilding.building.icon.replaceAll('\\', '/')}/>
&nbsp;{" "}<a href={`/mod/${props.modId}/race/${props.raceId}/building/${limitPerBuilding.building.id}`}>
{limitPerBuilding.building.name} </a> allow produce max {limitPerBuilding.limit}</span>
}
function renderRequirementResearches(requirementResearches: IResearchRequirements[],) {
return <div> {requirementResearches.map(rs => return <div> {requirementResearches.map(rs =>
<span>&nbsp; Research {rs.researchMustNotBeComplete ? "not" : ""}: <img style={{verticalAlign: "top", height: 25}} <span>&nbsp; Research {rs.researchMustNotBeComplete ? "not" : ""}: <img style={{verticalAlign: "top", height: 25}}
src={getIcon(rs.researchShortDto.icon)}/> src={getIcon(rs.researchShortDto.icon)}/>
&nbsp;<a href={`/mod/${modId}/race/${raceId}/building/${rs.researchShortDto.buildingId}#research-${rs.researchShortDto.id}`}> &nbsp;<a href={`/mod/${props.modId}/race/${props.raceId}/building/${rs.researchShortDto.buildingId}#research-${rs.researchShortDto.id}`}>
{rs.researchShortDto.name} {rs.researchShortDto.name}
</a></span> </a></span>
)}</div> )}</div>
} }
const requirement = props.requirement const requirement = props.requirement
const building = props.building
return ( return (
@ -66,21 +82,25 @@ function Required (props: IRequiredProps) {
{requirement.requireAddon !== null && {requirement.requireAddon !== null &&
<div>&nbsp; Addon: <img style={{verticalAlign: "top", height: 25}} <div>&nbsp; Addon: <img style={{verticalAlign: "top", height: 25}}
src={IconUrl + requirement.requireAddon.icon.replaceAll('\\', '/')}/>&nbsp; src={IconUrl + requirement.requireAddon.icon.replaceAll('\\', '/')}/>&nbsp;
<a href={"#addon-" + requirement.requireAddon.id} onClick={() => goToAddon(`#addon-` + requirement.requireAddon.id)}>{requirement.requireAddon.name}</a> <a href={`/mod/${props.modId}/race/${props.raceId}/building/${requirement.requireAddon.buildingId}#addon-${requirement.requireAddon.id}`}>
{requirement.requireAddon.name}
</a>
{requirement.replaceWhenDone && <i> (old provides replace)</i>} {requirement.replaceWhenDone && <i> (old provides replace)</i>}
</div> </div>
} }
{requirement.requirementBuildings.map(b => {requirement.requirementBuildings.map(b =>
<div>&nbsp; Building: <img style={{verticalAlign: "top", height: 25}} <div>&nbsp; Building: <img style={{verticalAlign: "top", height: 25}}
src={IconUrl + b.icon.replaceAll('\\', '/')}/>&nbsp; src={IconUrl + b.icon.replaceAll('\\', '/')}/>&nbsp;
<a href= {'/mod/'+ building.modId +'/race/'+ building.race.id +'/building/' + b.id + "/"}>{b.name}</a></div>) <a href= {'/mod/'+ props.modId +'/race/'+ props.raceId +'/building/' + b.id + "/"}>{b.name}</a></div>)
} }
{requirement.requirementResearches.length !== 0 && {requirement.requirementResearches.length !== 0 &&
renderRequirementResearches(requirement.requirementResearches, building.modId, building.race.id)} renderRequirementResearches(requirement.requirementResearches,)}
{requirement.requirementBuildingsEither.length !== 0 && {requirement.requirementBuildingsEither.length !== 0 &&
renderRequirementBuilding(requirement.requirementBuildingsEither, building, building.modId)} renderRequirementBuilding(requirement.requirementBuildingsEither,)}
{requirement.limitByBuilding !== undefined && requirement.limitByBuilding !== null && renderLimitPerBuilding(requirement.limitByBuilding)}
{requirement.requirementsGlobalAddons.length !== 0 && {requirement.requirementsGlobalAddons.length !== 0 &&
renderRequirementGlobalAddons(requirement.requirementsGlobalAddons, building, building.modId)} renderRequirementGlobalAddons(requirement.requirementsGlobalAddons,)}
{renderRequirementOwnership(requirement.requiredOwnership)}
</div> </div>
) )
} }

View File

@ -10,7 +10,7 @@ import {
TableBody, TableBody,
TableCell, TableCell,
TableContainer, TableContainer,
TableRow TableRow, Tooltip
} from "@mui/material"; } 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";
@ -20,6 +20,7 @@ import Vision from "./Vision";
import {IMod} from "../types/Imod"; import {IMod} from "../types/Imod";
import {renderAffectedResearches} from "./building/Research"; import {renderAffectedResearches} from "./building/Research";
import {Irace} from "../types/Irace"; import {Irace} from "../types/Irace";
import Required from "./Required";
@ -103,9 +104,8 @@ const Sergeant = (props: SergeantProps) => {
> >
<TableCell component="th" scope="row">Armor type</TableCell> <TableCell component="th" scope="row">Armor type</TableCell>
<TableCell component="th" scope="row"> <TableCell component="th" scope="row">
<ArmorType name={sergeant.armorType.name} compact={false}/> {sergeant.armorType2 == null ? <ArmorType name={sergeant.armorType.name} compact={false}/>
{sergeant.armorType2 && <span style={{fontSize: 12}} ><br/><i>after upgrade can become:<br/><ArmorType : <Tooltip title={"upgrade/debuff can turns to " + sergeant.armorType2.name}><span><ArmorType name={sergeant.armorType.name} compact={false}/></span></Tooltip> }
name={sergeant.armorType2.name} compact={false}/></i></span> }
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow <TableRow
@ -145,11 +145,15 @@ const Sergeant = (props: SergeantProps) => {
{sergeant.description} {sergeant.description}
</div> </div>
</Grid2> </Grid2>
{sergeant.requirements !== null &&
<Grid2 size={{xs: 12, md: 12}}>
<Required requirement={sergeant.requirements} modId={props.mod.id} raceId={props.race.id}/>
</Grid2>}
<Grid2 size={12}> <Grid2 size={12}>
{[...mapWithUnitWeapons.keys()].sort(function (a, b) { {[...mapWithUnitWeapons.keys()].sort(function (a, b) {
return a - b; return a - b;
}).map(h => <WeaponSlot race={props.race} mod={props.mod} unitWeapons={mapWithUnitWeapons.get(h)} hardpoint={h}/>)} }).map(h => <WeaponSlot key ={h} race={props.race} mod={props.mod} unitWeapons={mapWithUnitWeapons.get(h)} hardpoint={h}/>)}
</Grid2> </Grid2>
<Grid2 size={12}> <Grid2 size={12}>
{renderAffectedResearches(sergeant.affectedResearches, props.mod.id, props.race.id)} {renderAffectedResearches(sergeant.affectedResearches, props.mod.id, props.race.id)}

View File

@ -23,22 +23,22 @@ import Sergeant from "./Sergeant";
import {IMod} from "../types/Imod"; import {IMod} from "../types/Imod";
import {Irace} from "../types/Irace"; import {Irace} from "../types/Irace";
import {renderAffectedResearches} from "./building/Research"; import {renderAffectedResearches} from "./building/Research";
import Required from "./Required";
interface IWeaponProps { interface IWeaponProps {
weapon: IWeapon, weapon: IWeapon,
isDefault: Boolean, isDefault: Boolean,
renderRequired: Boolean,
mod: IMod, mod: IMod,
race: Irace, race: Irace,
} haveReinforceMenu: Boolean,
interface IWeaponState {
currentTable: "dps" | "one hit",
} }
class Weapon extends React.Component<IWeaponProps, any> { class Weapon extends React.Component<IWeaponProps, any> {
public static defaultProps = { public static defaultProps = {
isDefault: false isDefault: false,
renderRequired: true,
}; };
humanReadableName(unit: string) { humanReadableName(unit: string) {
@ -427,6 +427,10 @@ class Weapon extends React.Component<IWeaponProps, any> {
</TableContainer> </TableContainer>
<i className="rgdFrom">{weapon.filename}</i> <i className="rgdFrom">{weapon.filename}</i>
</Grid2> </Grid2>
{weapon.requirements !== null && !this.props.isDefault && this.props.haveReinforceMenu &&
<Grid2 size={{xs: 12, md: 12}}>
<Required requirement={weapon.requirements} modId={this.props.mod.id} raceId={this.props.race.id}/>
</Grid2>}
<Grid2 size={12}> <Grid2 size={12}>
{renderAffectedResearches(weapon.affectedResearches, this.props.mod.id, this.props.race.id)} {renderAffectedResearches(weapon.affectedResearches, this.props.mod.id, this.props.race.id)}
</Grid2> </Grid2>

View File

@ -9,7 +9,7 @@ export interface WeaponSlotProps {
unitWeapons: Map<number, IWeapon> | undefined, unitWeapons: Map<number, IWeapon> | undefined,
mod: IMod, mod: IMod,
race: Irace, race: Irace,
showOnlyDefault?: boolean , haveReinforceMenu?: boolean ,
} }
const WeaponSlot= (props: WeaponSlotProps) => { const WeaponSlot= (props: WeaponSlotProps) => {
@ -26,26 +26,16 @@ const WeaponSlot= (props: WeaponSlotProps) => {
let onlyDummy = weaponsSorted.filter(wp => !wp[1].filename.includes("dummy")).length === 0 let onlyDummy = weaponsSorted.filter(wp => !wp[1].filename.includes("dummy")).length === 0
let haveReinforceMenu = props.haveReinforceMenu === true
if(onlyDummy) return (<div></div>) if(onlyDummy) return (<div></div>)
if(props.showOnlyDefault){
if(firstWeapon.filename.includes("dummy")) return (<div></div>);
return (
<div>
<h3>{header}</h3>
<div style={{marginLeft: 20}}><Weapon race={props.race} mod={props.mod} isDefault={true} weapon={firstWeapon}/></div>
</div>
)
}
return ( return (
<div> <div>
<h3>{header}</h3> <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]}/></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>
)} )}
</div> </div>
) )

View File

@ -12,53 +12,11 @@ import {
TableRow TableRow
} from "@mui/material"; } from "@mui/material";
import {IBuilding, IBuildingAddon} from "../../types/IBuilding"; import {IBuilding, IBuildingAddon} from "../../types/IBuilding";
import {WeaponHardpoint} from "../../types/IUnit";
import AvTimerOutlinedIcon from "@mui/icons-material/AvTimer"; import AvTimerOutlinedIcon from "@mui/icons-material/AvTimer";
import WeaponSlot from "../WeaponSlot";
import {ExpandMore} from "@mui/icons-material"; import {ExpandMore} from "@mui/icons-material";
import {IMod} from "../../types/Imod"; import {IMod} from "../../types/Imod";
import {IModifier} from "../../types/IModifier"; import {getIcon, ModifiersProvidesTable,} from "../ModifiersProvideTable";
import {getIcon, ModifiersProvidesAddonTable,} from "../ModifiersProvideTable";
import Required from "../Required"; import Required from "../Required";
import {Irace} from "../../types/Irace";
interface IAddonModifiersProvidesWeapons{
modifiers: IModifier[],
replacedAddonModifiers: IModifier[],
weapons: WeaponHardpoint[],
mod: IMod,
race: Irace
}
function AddonModifiersProvidesWeapons (props: IAddonModifiersProvidesWeapons) {
function getWeaponByAddonMod(ar: IModifier){
let hardpoint = Number(ar.reference.replace("modifiers\\default_weapon_modifier_hardpoint", "").replace(".lua", ""));
let value = ar.value;
//let prevAddonWeaponMod = props.replacedAddonModifiers.find(m => m.reference && m.reference.includes("modifiers\\default_weapon_modifier_hardpoint" + hardpoint))?.value ?? 0
let weapon = props.weapons.find(w => w.hardpoint === hardpoint && w.hardpointOrder === 1 + value )?.weapon
if (weapon != null){
return <WeaponSlot race={props.race} mod={props.mod} unitWeapons={new Map().set(hardpoint, weapon)} hardpoint={hardpoint}/>;
}else{
return "Can't find weapon, replaced by addon:" + value + " - "
}
}
let weaponMods = props.modifiers.filter(m => m.reference.includes("default_weapon_modifier_hardpoint"))
return (
<div>
{weaponMods.map(w => getWeaponByAddonMod(w))}
</div>
)
}
interface IBuildingAddonProps { interface IBuildingAddonProps {
addon: IBuildingAddon, addon: IBuildingAddon,
@ -72,12 +30,6 @@ function BuildingAddon(props: IBuildingAddonProps){
const building = props.building const building = props.building
const prevAddonModifiers: IModifier[] = (function() {
if (addon.addonRequirement && addon.addonRequirement.requireAddon !== null && !addon.addonRequirement.replaceWhenDone){
return building.addons.find(a => a.id === addon.addonRequirement.requireAddon.id)?.addonModifiers ?? [];
} else return [];
})()
return <div className='addon-research-accordion' id={"addon-" + addon.id} ><Accordion> return <div className='addon-research-accordion' id={"addon-" + addon.id} ><Accordion>
<AccordionSummary <AccordionSummary
@ -129,20 +81,16 @@ function BuildingAddon(props: IBuildingAddonProps){
</TableBody> </TableBody>
</Table> </Table>
</TableContainer><br/> </TableContainer><br/>
<ModifiersProvidesAddonTable modifiers={addon.addonModifiers}/>
</Grid2> </Grid2>
<Grid2 size={{xs: 12, md: 8}}> <Grid2 size={{xs: 12, md: 8}}>
<div style={{whiteSpace: "pre-wrap"}}> <div style={{whiteSpace: "pre-wrap"}}>
{addon.description} {addon.description}
</div> </div>
</Grid2> </Grid2>
{addon.addonModifiers !== null && <ModifiersProvidesTable modifiers={addon.addonModifiers} affectedData={addon.affectedData} mod={props.mod} race={building.race}/>
<Grid2 size={{xs: 12, md: 12}}>
<AddonModifiersProvidesWeapons race={building.race} mod={props.mod} modifiers={addon.addonModifiers} replacedAddonModifiers={prevAddonModifiers} weapons={building.weapons}/>
</Grid2>}
{addon.addonRequirement !== null && {addon.addonRequirement !== null &&
<Grid2 size={{xs: 12, md: 12}}> <Grid2 size={{xs: 12, md: 12}}>
<Required requirement={addon.addonRequirement} building={building}/> <Required requirement={addon.addonRequirement} modId={building.modId} raceId={building.race.id}/>
</Grid2>} </Grid2>}
</Grid2> </Grid2>
<i className="rgdFrom">{addon.filename}</i> <i className="rgdFrom">{addon.filename}</i>

View File

@ -13,7 +13,7 @@ import {
TableRow TableRow
} from "@mui/material"; } from "@mui/material";
import {ExpandMore} from "@mui/icons-material"; import {ExpandMore} from "@mui/icons-material";
import {getIcon, ModifiersProvidesResearchTable} from "../ModifiersProvideTable"; import {getIcon, ModifiersProvidesTable} from "../ModifiersProvideTable";
import AvTimerOutlinedIcon from "@mui/icons-material/AvTimer"; import AvTimerOutlinedIcon from "@mui/icons-material/AvTimer";
import Required from "../Required"; import Required from "../Required";
import React from "react"; import React from "react";
@ -90,11 +90,11 @@ function ResearchFull(props: IResearchProps){
</Grid2> </Grid2>
<Grid2 size={{xs: 12, md: 12}}> <Grid2 size={{xs: 12, md: 12}}>
<ModifiersProvidesResearchTable modifiers={research.modifiers} research={research} race={building.race}/> <ModifiersProvidesTable modifiers={research.modifiers} affectedData={research.affectedData} mod={props.mod} race={building.race}/>
</Grid2> </Grid2>
{research.requirements !== null && {research.requirements !== null &&
<Grid2 size={{xs: 12, md: 12}}> <Grid2 size={{xs: 12, md: 12}}>
<Required requirement={research.requirements} building={building}/> <Required requirement={research.requirements} modId={building.modId} raceId={building.race.id}/>
</Grid2>} </Grid2>}
</Grid2> </Grid2>
<i className="rgdFrom">{research.filename}</i> <i className="rgdFrom">{research.filename}</i>
@ -114,8 +114,8 @@ export function renderAffectedResearches(researches: IResearchShort[], modId: nu
} }
return <div> {researches.map(rs => return <div> {researches.map(rs =>
rs.buildingId == null ? <span></span> : rs.buildingId == null ? <span key={rs.id}></span> :
<span>Research affect: {researchLink(rs)}<br/></span> <span key={rs.id}>Research affect: {researchLink(rs)}<br/></span>
)}</div> )}</div>
} }

View File

@ -1,5 +1,5 @@
import {AvailableBuildings, AvailableMods, IconUrl} from "../core/api"; import {AvailableBuildings, AvailableMods, IconUrl} from "../core/api";
import React from "react"; import React, {useEffect} from "react";
import {withRouter} from "../core/withrouter"; import {withRouter} from "../core/withrouter";
import {IWeapon} from "../types/IUnit"; import {IWeapon} from "../types/IUnit";
import '../css/Building.css' import '../css/Building.css'
@ -13,7 +13,7 @@ import {
TableBody, TableBody,
TableCell, TableCell,
TableContainer, TableContainer,
TableRow TableRow, Tooltip
} from "@mui/material"; } from "@mui/material";
import {ArrowBack} from "@mui/icons-material"; import {ArrowBack} from "@mui/icons-material";
import ArmorType from "../classes/ArmorType"; import ArmorType from "../classes/ArmorType";
@ -26,6 +26,7 @@ import Vision from "../classes/Vision";
import BuildingAddon from "../classes/building/BuildingAddon"; import BuildingAddon from "../classes/building/BuildingAddon";
import {IUnitShort} from "../types/IUnitShort"; import {IUnitShort} from "../types/IUnitShort";
import Research, {renderAffectedResearches} from "../classes/building/Research"; import Research, {renderAffectedResearches} from "../classes/building/Research";
import Required from "../classes/Required";
interface UintPageState { interface UintPageState {
building: IBuilding, building: IBuilding,
@ -34,18 +35,19 @@ interface UintPageState {
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}><ListItem> return (<Grid2 size={{xs: 12, md: 3}}><Link href={"/mod/" + modId + "/race/" + raceId + "/unit/" + unit.id}><ListItem>
{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>&nbsp;<img style={{verticalAlign: "top"}} {unit.canDetect && <span>&nbsp;<img style={{verticalAlign: "top"}}
src="/images/DETECT_YES.webp"/></span>} src="/images/DETECT_YES.webp"/></span>}
</ListItem></Link></Grid2>)
</ListItem></Link>)
} }
function Building(building: IBuilding, mod: IMod) { function Building(building: IBuilding, mod: IMod) {
document.title = building.name
let mapBuildingWeapons: Map<number, Map<number, IWeapon>> = new Map(); let mapBuildingWeapons: Map<number, Map<number, IWeapon>> = new Map();
@ -130,8 +132,8 @@ function Building(building: IBuilding, mod: IMod) {
> >
<TableCell component="th" scope="row">Armor type</TableCell> <TableCell component="th" scope="row">Armor type</TableCell>
<TableCell component="th" scope="row"> <TableCell component="th" scope="row">
<ArmorType name={building.armorType.name} compact={false}/> {building.armorType2 == null ? <ArmorType name={building.armorType.name} compact={false}/>
{building.armorType2 && <span><br/><ArmorType name={building.armorType2.name} compact={false}/></span> } : <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
@ -170,11 +172,17 @@ function Building(building: IBuilding, mod: IMod) {
{building.description} {building.description}
</div> </div>
</Grid2> </Grid2>
{building.requirements !== null &&
<Grid2 size={{xs: 12, md: 12}}>
<Required requirement={building.requirements} modId={building.modId} raceId={building.race.id}/>
</Grid2>}
{building.units.length > 0 && <Grid2 size={12}> {building.units.length > 0 && <Grid2 size={12}>
<h3>Unit production</h3> <h3>Unit production</h3>
<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)
)} )}
</Grid2>
</Grid2>} </Grid2>}
{building.addons.length > 0 && <Grid2 size={12}> {building.addons.length > 0 && <Grid2 size={12}>
<h3>Addons</h3> <h3>Addons</h3>
@ -191,7 +199,7 @@ function Building(building: IBuilding, mod: IMod) {
<Grid2 size={12}> <Grid2 size={12}>
{[...mapBuildingWeapons.keys()].sort(function (a, b) { {[...mapBuildingWeapons.keys()].sort(function (a, b) {
return a - b; return a - b;
}).map(h => <WeaponSlot race={building.race} mod={mod} showOnlyDefault={true} unitWeapons={mapBuildingWeapons.get(h)} hardpoint={h}/>)} }).map(h => <WeaponSlot race={building.race} mod={mod} unitWeapons={mapBuildingWeapons.get(h)} hardpoint={h}/>)}
</Grid2> </Grid2>
<Grid2 size={12}> <Grid2 size={12}>
{renderAffectedResearches(building.affectedResearches, mod.id, building.race.id)} {renderAffectedResearches(building.affectedResearches, mod.id, building.race.id)}
@ -203,25 +211,6 @@ function Building(building: IBuilding, mod: IMod) {
</div>) </div>)
} }
function goToAddon(addonHash: string) {
let addonId = addonHash.replace("#", "");
[].forEach.call(document.querySelectorAll('div'), function (el: HTMLElement) {
el?.classList?.remove('selected-addon');
});
document?.getElementById(addonId)?.classList?.add("selected-addon");
document?.getElementById(addonId)?.scrollIntoView()
}
function goToResearch(researchHash: string) {
let researchId = researchHash.replace("#", "");
[].forEach.call(document.querySelectorAll('div'), function (el: HTMLElement) {
el?.classList?.remove('selected-research');
});
document?.getElementById(researchId)?.classList?.add("selected-research");
document?.getElementById(researchId)?.scrollIntoView()
}
class BuildingPage extends React.Component<any, UintPageState> { class BuildingPage extends React.Component<any, UintPageState> {
async componentDidMount() { async componentDidMount() {
@ -238,8 +227,6 @@ class BuildingPage extends React.Component<any, UintPageState> {
this.setState({ this.setState({
mod: modData mod: modData
}); });
goToAddon(window.location.hash);
goToResearch(window.location.hash);
} }
render() { render() {
@ -258,5 +245,3 @@ class BuildingPage extends React.Component<any, UintPageState> {
} }
export default withRouter(BuildingPage); export default withRouter(BuildingPage);
export { goToAddon, goToResearch };

View File

@ -35,6 +35,8 @@ class ModPage extends React.Component<any, ModPageState> {
render() { render() {
if(this.state != null && this.state.mod != null ){ if(this.state != null && this.state.mod != null ){
document.title = this.state.mod.name
return <div> return <div>
<a href="/"><Button id="back-button" variant="contained" <a href="/"><Button id="back-button" variant="contained"
startIcon={<ArrowBack/>}> Back</Button></a> startIcon={<ArrowBack/>}> Back</Button></a>

View File

@ -39,10 +39,10 @@ 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}><ListItem> return (<Link href={"/mod/" + modId + "/race/" + raceId + "/unit/" + unit.id}><ListItem>
{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>&nbsp;<img style={{verticalAlign: "top"}} {unit.canDetect && <span>&nbsp;<img style={{verticalAlign: "top"}}
src="/images/DETECT_YES.webp"/></span>} src="/images/DETECT_YES.webp"/></span>}
@ -50,7 +50,7 @@ function Unit (unit: IUnitShort, modId: number, raceId: String) {
</ListItem></Link>) </ListItem></Link>)
} }
function UnitSmall (unit: IUnitShort, modId: number, raceId: String) { function UnitSmall(unit: IUnitShort, modId: number, raceId: String) {
var unitName = "" var unitName = ""
if (unit.name.length > 21) { if (unit.name.length > 21) {
@ -66,7 +66,7 @@ function UnitSmall (unit: IUnitShort, modId: number, raceId: String) {
src="/images/DETECT_YES.webp"/></span>}<br/></Link>) 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}}><Link href={"/mod/" + modId + "/race/" + raceId + "/building/" + building.id}><ListItem> return (<Grid2 size={{xs: 12, md: 3}}><Link href={"/mod/" + modId + "/race/" + raceId + "/building/" + building.id}><ListItem>
{building.icon && <img className="unitIcon" src={IconUrl + building.icon.replaceAll('\\', '/')}/>} {building.icon && <img className="unitIcon" src={IconUrl + building.icon.replaceAll('\\', '/')}/>}
@ -74,16 +74,15 @@ function Building (building: IBuildingShort, modId: number, raceId: String) {
{building.canDetect && <span>&nbsp;<img style={{verticalAlign: "top"}} {building.canDetect && <span>&nbsp;<img style={{verticalAlign: "top"}}
src="/images/DETECT_YES.webp"/></span>} src="/images/DETECT_YES.webp"/></span>}
</ListItem></Link> </ListItem></Link>
{building.units.map(unit => UnitSmall(unit, modId, raceId))} {building.units.map(unit => UnitSmall(unit, modId, raceId))}
</Grid2>) </Grid2>)
} }
interface UnitsProps{ interface UnitsProps {
raceId: string, raceId: string,
modId: number, modId: number,
} }
interface UnitsState { interface UnitsState {
selectedUnits: String | null, selectedUnits: String | null,
@ -95,6 +94,7 @@ class Units extends React.Component<UnitsProps, UnitsState> {
constructor(props: any) { constructor(props: any) {
super(props); super(props);
let urlUnits = AvailableUnits + "/" + this.props.modId + "/" + this.props.raceId; let urlUnits = AvailableUnits + "/" + this.props.modId + "/" + this.props.raceId;
@ -118,18 +118,24 @@ class Units extends React.Component<UnitsProps, UnitsState> {
}) })
} }
render () { render() {
if (this.state && this.state.units) { if (this.state && this.state.units) {
return (<div> if(this.state.buildings?.race.name !== undefined){
document.title = this.state.buildings?.race.name
}
{this.state.units != null && this.state.buildings != null ? return (this.state.buildings != null ?
<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>
{this.state.buildings.buildingsAdvanced.length > 0 && <div><hr/><Grid2 container spacing={2}>
{this.state.buildings.buildingsAdvanced.map(building => Building(building, this.props.modId, this.props.raceId))}
</Grid2><br/></div>}
<Grid2>
<Grid2 size={{xs: 12, md: 12}}> <Grid2 size={{xs: 12, md: 12}}>
<Accordion> <Accordion>
<AccordionSummary <AccordionSummary
@ -141,19 +147,27 @@ class Units extends React.Component<UnitsProps, UnitsState> {
</AccordionSummary> </AccordionSummary>
<AccordionDetails> <AccordionDetails>
<Grid2 container spacing={2}> <Grid2 container spacing={2}>
<Grid2 size= {{xs: 12, md: 4}}> <Grid2 size={{xs: 12, md: 4}}>
<h3>Infantry</h3> <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}}>
<h3>Tech</h3> <h3>Tech</h3>
<List sx={{width: '100%', maxWidth: 360, bgcolor: 'background.paper'}}> <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}}>
<h3>Support</h3> <h3>Support</h3>
<List sx={{width: '100%', maxWidth: 360, bgcolor: 'background.paper'}}> <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>
@ -162,9 +176,8 @@ class Units extends React.Component<UnitsProps, UnitsState> {
</Accordion> </Accordion>
</Grid2><br/> </Grid2><br/>
</Grid2> </Grid2>
: "Loading"} </div> : "Loading"
)
</div>)
} else { } else {
return "Loading..."; return "Loading...";
} }
@ -192,16 +205,17 @@ class RacePageFast extends React.Component<any, RacePageState> {
const racesData: Irace = await response.json(); const racesData: Irace = await response.json();
this.setState({ this.setState({
race : racesData race: racesData
}); });
} }
render() { render() {
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 <div><Link href={backRef}><Button id="back-button" variant="contained" startIcon={<ArrowBack/>}> Back</Button></Link> return <div><Link href={backRef}><Button id="back-button" variant="contained"
startIcon={<ArrowBack/>}> Back</Button></Link>
<h1>{this.state.mod.name} ({this.state.mod.version}) - {this.state.race.name}</h1> <h1>{this.state.mod.name} ({this.state.mod.version}) - {this.state.race.name}</h1>
<Units raceId={this.state.race.id} modId={this.state.mod.id}/> <Units raceId={this.state.race.id} modId={this.state.mod.id}/>
</div>; </div>;

View File

@ -14,7 +14,8 @@ import {
TableBody, TableBody,
TableCell, TableCell,
TableContainer, TableContainer,
TableRow TableRow,
Tooltip
} 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";
@ -24,9 +25,7 @@ import WeaponSlot from "../classes/WeaponSlot";
import UnitsTable from "../classes/UnitsTable"; import UnitsTable from "../classes/UnitsTable";
import {IMod} from "../types/Imod"; import {IMod} from "../types/Imod";
import Vision from "../classes/Vision"; import Vision from "../classes/Vision";
import {IResearchRequirements} from "../types/IResearchRequirements"; import Required from "../classes/Required";
import {getIcon} from "../classes/Required";
import {IResearchShort} from "../types/IResearchShort";
import {renderAffectedResearches} from "../classes/building/Research"; import {renderAffectedResearches} from "../classes/building/Research";
interface UintPageState { interface UintPageState {
@ -37,6 +36,8 @@ interface UintPageState {
function Unit(unit: IUnit, mod: IMod) { function Unit(unit: IUnit, mod: IMod) {
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"/>&nbsp;{unit.moraleMax} <img style={{verticalAlign: "top"}} src="/images/ARM_Morale.webp"/>&nbsp;{unit.moraleMax}
+{unit.moraleRegeneration}/s +{unit.moraleRegeneration}/s
@ -77,10 +78,6 @@ function Unit(unit: IUnit, mod: IMod) {
} }
console.log(unit);
return ( return (
<div> <div>
<h1>{mod.name} ({mod.version})</h1> <h1>{mod.name} ({mod.version})</h1>
@ -192,9 +189,7 @@ function Unit(unit: IUnit, mod: IMod) {
> >
<TableCell component="th" scope="row">Armor type</TableCell> <TableCell component="th" scope="row">Armor type</TableCell>
<TableCell component="th" scope="row"> <TableCell component="th" scope="row">
<ArmorType name={unit.armorType.name} compact={false}/> {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 && <span style={{fontSize: 12}} ><br/><i>after upgrade can become:<br/><ArmorType
name={unit.armorType2.name} compact={false}/></i></span> }
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow <TableRow
@ -257,6 +252,14 @@ function Unit(unit: IUnit, mod: IMod) {
</TableCell> </TableCell>
</TableRow> </TableRow>
} }
{unit.squadLimit !== undefined && unit.squadLimit !== null &&
<TableRow>
<TableCell>Limit</TableCell>
<TableCell>
{unit.squadLimit}
</TableCell>
</TableRow>
}
</TableBody> </TableBody>
</Table> </Table>
</TableContainer> </TableContainer>
@ -266,9 +269,13 @@ function Unit(unit: IUnit, mod: IMod) {
{unit.description} {unit.description}
</div> </div>
</Grid2> </Grid2>
{unit.requirements !== null &&
<Grid2 size={{xs: 12, md: 12}}>
<Required requirement={unit.requirements} modId={unit.modId} raceId={unit.race.id}/>
</Grid2>}
<Grid2 size={12}> <Grid2 size={12}>
{unit.sergeants.map(s => {unit.sergeants.map(s =>
<Accordion> <Accordion key={s.id}>
<AccordionSummary <AccordionSummary
expandIcon={<ExpandMore/>} expandIcon={<ExpandMore/>}
aria-controls="panel1-content" aria-controls="panel1-content"
@ -286,7 +293,7 @@ function Unit(unit: IUnit, mod: IMod) {
<Grid2 size={12}> <Grid2 size={12}>
{[...mapWithUnitWeapons.keys()].sort(function (a, b) { {[...mapWithUnitWeapons.keys()].sort(function (a, b) {
return a - b; return a - b;
}).map(h => <WeaponSlot race={unit.race} mod={mod} unitWeapons={mapWithUnitWeapons.get(h)} hardpoint={h}/>)} }).map(h => <WeaponSlot haveReinforceMenu={unit.haveReinforceMenu} key ={h} race={unit.race} mod={mod} unitWeapons={mapWithUnitWeapons.get(h)} hardpoint={h}/>)}
</Grid2> </Grid2>
<Grid2 size={12}> <Grid2 size={12}>
{renderAffectedResearches(unit.affectedResearches, mod.id, unit.race.id)} {renderAffectedResearches(unit.affectedResearches, mod.id, unit.race.id)}
@ -325,12 +332,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 <div><a href={backRef}><Button id="back-button" variant="contained" return <div key={this.state.unit.id}><a href={backRef}><Button id="back-button" variant="contained"
startIcon={<ArrowBack/>}> Back</Button></a> startIcon={<ArrowBack/>}> Back</Button></a>
{Unit(this.state.unit, this.state.mod)} {Unit(this.state.unit, this.state.mod)}
</div>; </div>;
} else { } else {
return "loading..."; return <div key = {'loading'}>loading...</div>;
} }
} }
} }

View File

@ -0,0 +1,10 @@
import {IModifier} from "./IModifier";
import {IRequirement} from "./IRequirement";
import {IAffectedEntity, ISergeantUnitShortDto, IWeaponUnitShortDto} from "./IAffectedEntity";
export interface IAffectedData {
affectedUnits: IAffectedEntity[]
affectedSergeants: ISergeantUnitShortDto[]
affectedBuildings: IAffectedEntity[]
affectedWeapons: IWeaponUnitShortDto[]
}

View File

@ -6,6 +6,7 @@ import {IModifier} from "./IModifier";
import {IRequirement} from "./IRequirement"; import {IRequirement} from "./IRequirement";
import {IResearch} from "./IResearch"; import {IResearch} from "./IResearch";
import {IResearchShort} from "./IResearchShort"; import {IResearchShort} from "./IResearchShort";
import {IAffectedData} from "./IAffectedData";
export interface IBuilding { export interface IBuilding {
id: number id: number
@ -37,6 +38,7 @@ export interface IBuilding {
researches: IResearch[] researches: IResearch[]
units: IUnitShort[] units: IUnitShort[]
affectedResearches: IResearchShort[], affectedResearches: IResearchShort[],
requirements: IRequirement,
} }
export interface IBuildingAddon { export interface IBuildingAddon {
@ -50,6 +52,7 @@ export interface IBuildingAddon {
addonCostFaith: number; addonCostFaith: number;
addonCostSouls: number; addonCostSouls: number;
addonCostTime: number; addonCostTime: number;
affectedData: IAffectedData;
addonModifiers: IModifier[]; addonModifiers: IModifier[];
addonRequirement: IRequirement; addonRequirement: IRequirement;
icon?: string; icon?: string;

View File

@ -4,6 +4,7 @@ import {IUnitShort} from "./IUnitShort";
export interface IRaceBuildings { export interface IRaceBuildings {
race: Irace race: Irace
buildings: IBuildingShort[] buildings: IBuildingShort[]
buildingsAdvanced: IBuildingShort[]
} }
export interface IBuildingShort { export interface IBuildingShort {
@ -12,5 +13,6 @@ export interface IBuildingShort {
id: number id: number
units: IUnitShort[] units: IUnitShort[]
canDetect: boolean canDetect: boolean
armorTypeName: string armorTypeName: string,
uiIndexHint: number,
} }

View File

@ -10,4 +10,13 @@ export interface IRequirement {
replaceWhenDone: Boolean; replaceWhenDone: Boolean;
requireAddon: IBuildingAddonShort; requireAddon: IBuildingAddonShort;
requiredTotalPop?: number; requiredTotalPop?: number;
limitSquad?:number;
limitTech?:number;
limitByBuilding ?: IRequirementLimitByBuildingDto;
requiredOwnership: string[];
}
export interface IRequirementLimitByBuildingDto{
building: IBuildingShort;
limit: number;
} }

View File

@ -1,6 +1,6 @@
import {IModifier} from "./IModifier"; import {IModifier} from "./IModifier";
import {IRequirement} from "./IRequirement"; import {IRequirement} from "./IRequirement";
import {IAffectedEntity, ISergeantUnitShortDto, IWeaponUnitShortDto} from "./IAffectedEntity"; import {IAffectedData} from "./IAffectedData";
export interface IResearch { export interface IResearch {
id: number id: number
@ -15,10 +15,7 @@ export interface IResearch {
costTime: number costTime: number
icon: string icon: string
modId: number modId: number
affectedUnits: IAffectedEntity[] affectedData: IAffectedData
affectedSergeants: ISergeantUnitShortDto[]
affectedBuildings: IAffectedEntity[]
affectedWeapons: IWeaponUnitShortDto[]
requirements: IRequirement requirements: IRequirement
modifiers: IModifier[] modifiers: IModifier[]
} }

View File

@ -1,6 +1,7 @@
import {Irace} from "./Irace"; import {Irace} from "./Irace";
import {IArmorType} from "./IArmorType"; import {IArmorType} from "./IArmorType";
import {IResearchShort} from "./IResearchShort"; import {IResearchShort} from "./IResearchShort";
import {IRequirement} from "./IRequirement";
export interface IUnitResponse { export interface IUnitResponse {
race: string race: string
@ -52,6 +53,8 @@ export interface IUnit {
requisitionIncome?: number requisitionIncome?: number
icon: string icon: string
modId: number modId: number
requirements: IRequirement
haveReinforceMenu: boolean,
sergeants: ISergeant[] sergeants: ISergeant[]
weapons: WeaponHardpoint[] weapons: WeaponHardpoint[]
affectedResearches: IResearchShort[], affectedResearches: IResearchShort[],
@ -82,6 +85,7 @@ export interface ISergeant {
sightRadius: number sightRadius: number
detectRadius: number detectRadius: number
icon: string icon: string
requirements: IRequirement,
weapons: WeaponHardpoint[] weapons: WeaponHardpoint[]
affectedResearches: IResearchShort[], affectedResearches: IResearchShort[],
} }
@ -117,9 +121,10 @@ export interface IWeapon {
isMeleeWeapon: boolean isMeleeWeapon: boolean
canAttackAir: boolean canAttackAir: boolean
canAttackGround: boolean canAttackGround: boolean
haveEquipButton: boolean showInReinforce: boolean
icon: string icon: string
modId: number modId: number
requirements: IRequirement
weaponArmorPiercing: IWeaponPiercing[] weaponArmorPiercing: IWeaponPiercing[]
affectedResearches: IResearchShort[], affectedResearches: IResearchShort[],
} }