Complete addons

This commit is contained in:
Anibus 2025-06-07 23:43:02 +03:00
parent ba699a0199
commit 00963ddc56
11 changed files with 328 additions and 165 deletions

4
.env
View File

@ -1,2 +1,2 @@
REACT_APP_HOST_URL=http://wiki-backend.dawn-of-war.pro #REACT_APP_HOST_URL=http://wiki-backend.dawn-of-war.pro
#REACT_APP_HOST_URL=http://localhost:8082 REACT_APP_HOST_URL=http://localhost:8082

BIN
public/images/defence.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -16,6 +16,7 @@ import AvTimerOutlinedIcon from "@mui/icons-material/AvTimer";
import ArmorType from "./ArmorType"; import ArmorType from "./ArmorType";
import {ExpandMore} from "@mui/icons-material"; import {ExpandMore} from "@mui/icons-material";
import WeaponSlot from "./WeaponSlot"; import WeaponSlot from "./WeaponSlot";
import Vision from "./Vision";
@ -27,11 +28,6 @@ const Sergeant = (props: SergeantProps) => {
const sergeant = props.sergeant const sergeant = props.sergeant
const detect = sergeant.detectRadius > 0 ? <span>&nbsp;<img style={{verticalAlign: "top"}}
src="/images/DETECT_YES.webp"/> {sergeant.detectRadius}</span> :
<span>&nbsp;<img style={{verticalAlign: "top"}}
src="/images/DETECT_NO.webp"/></span>
let mapWithUnitWeapons: Map<number, Map<number, IWeapon>> = new Map(); let mapWithUnitWeapons: Map<number, Map<number, IWeapon>> = new Map();
sergeant.weapons.forEach(weapon => { sergeant.weapons.forEach(weapon => {
@ -111,7 +107,7 @@ const Sergeant = (props: SergeantProps) => {
> >
<TableCell component="th" scope="row">detect</TableCell> <TableCell component="th" scope="row">detect</TableCell>
<TableCell component="th" scope="row"> <TableCell component="th" scope="row">
{detect} <Vision sight={sergeant.sightRadius} detect={sergeant.detectRadius}/>
</TableCell> </TableCell>
</TableRow> </TableRow>
</TableBody> </TableBody>

25
src/classes/Vision.tsx Normal file
View File

@ -0,0 +1,25 @@
import React from "react";
import {Tooltip} from "@mui/material";
interface IVision{
sight: number,
detect: number
}
function Vision (vision: IVision) {
return (
<div>
<Tooltip title="Sight">
<span><img style={{verticalAlign: "top"}}
src="/images/DETECT_NO.webp"/>{vision.sight}</span>
</Tooltip>
{vision.detect !== 0 && <Tooltip title="Detect">
<span><img style={{verticalAlign: "top"}}
src="/images/DETECT_YES.webp"/>{vision.detect}</span>
</Tooltip>}
</div>
)
}
export default Vision;

View File

@ -4,7 +4,8 @@ import {IWeapon} from "../types/IUnit";
export interface WeaponSlotProps { export interface WeaponSlotProps {
hardpoint: number, hardpoint: number,
unitWeapons: Map<number, IWeapon> | undefined unitWeapons: Map<number, IWeapon> | undefined,
showOnlyDefault?: boolean ,
} }
const WeaponSlot= (props: WeaponSlotProps) => { const WeaponSlot= (props: WeaponSlotProps) => {
@ -23,6 +24,18 @@ const WeaponSlot= (props: WeaponSlotProps) => {
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 isDefault={true} weapon={firstWeapon}/></div>
</div>
)
}
return ( return (
<div> <div>
<h3>{header}</h3> <h3>{header}</h3>

View File

@ -0,0 +1,262 @@
import React from "react";
import {
Accordion,
AccordionDetails,
AccordionSummary,
Grid2,
Paper,
Table,
TableBody,
TableCell,
TableContainer,
TableRow
} from "@mui/material";
import {IAddonModifier, IBuilding, IBuildingAddon, IBuildingAddonShort} from "../../types/IBuilding";
import {WeaponHardpoint} from "../../types/IUnit";
import AvTimerOutlinedIcon from "@mui/icons-material/AvTimer";
import WeaponSlot from "../WeaponSlot";
import {ExpandMore} from "@mui/icons-material";
import {IconUrl} from "../../core/api";
import {IBuildingShort} from "../../types/IBuildingShort";
import {goToAddon} from "../../pages/BuildingPage";
interface IAddonModifiersProvidesTable{
modifiers: IAddonModifier[],
}
function AddonModifiersProvidesTable (props: IAddonModifiersProvidesTable) {
function getModName(mt: String){
switch(mt) {
case 'modifiers\\armour_modifier.lua':
return 'Armor';
case 'modifiers\\health_maximum_modifier.lua':
return 'Health';
case 'modifiers\\keen_sight_radius_modifier.lua':
return 'Detect';
case 'modifiers\\garrison_requisition_modifier.lua':
return 'Requisition';
default:
return mt;
}
}
function getModIcon(mt: String){
switch(mt) {
case 'modifiers\\armour_modifier.lua':
return <img style={{height: 20, verticalAlign: "top"}} src='/images/defence.png'/>;
case 'modifiers\\health_maximum_modifier.lua':
return <img style={{verticalAlign: "top"}} src='/images/Health_icon.webp'/>;
case 'modifiers\\keen_sight_radius_modifier.lua':
return <img style={{verticalAlign: "top"}} src='/images/DETECT_YES.webp'/>;
case 'modifiers\\garrison_requisition_modifier.lua':
return <img style={{verticalAlign: "top"}} src='/images/Resource_requisition.gif'/>;
default:
return mt;
}
}
function getChangeDescription(ref: String) {
switch(ref) {
case 'type_modifierusagetype\\tp_mod_usage_addition.lua':
return '+';
case 'type_modifierusagetype\\tp_mod_usage_multiplication.lua':
return 'x';
case 'type_modifierusagetype\\tp_mod_usage_percentage.lua':
return '%';
case 'type_modifierusagetype\\tp_mod_usage_enable.lua':
return ' enable ';
default:
return ref;
}
}
let noWeaponMods = props.modifiers.filter(m => !m.reference.includes("default_weapon_modifier_hardpoint"))
return (
<TableContainer component={Paper}>
<Table size="small" aria-label="a dense table">
{noWeaponMods.map(m =>
<TableRow
sx={{'&:last-child td, &:last-child th': {border: 0}}}
>
<TableCell component="th" scope="row">{getModName(m.reference)}</TableCell>
<TableCell component="th" scope="row">{getModIcon(m.reference)} {getChangeDescription(m.usageType)}{m.value}</TableCell>
</TableRow>
)}
</Table>
</TableContainer>
)
}
interface IAddonModifiersProvidesWeapons{
modifiers: IAddonModifier[],
replacedAddonModifiers: IAddonModifier[],
weapons: WeaponHardpoint[]
}
function AddonModifiersProvidesWeapons (props: IAddonModifiersProvidesWeapons) {
function getWeaponByAddonMod(ar: IAddonModifier){
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 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 {
addon: IBuildingAddon,
building: IBuilding
}
function BuildingAddon(props: IBuildingAddonProps){
const addon = props.addon
const building = props.building
const prevAddonModifiers: IAddonModifier[] = (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 [];
})()
function renderRequirementBuilding(requirementBuildings: IBuildingShort[], building: IBuilding) {
return requirementBuildings.length > 0 && (
<div>&nbsp; Buildings: <img style={{verticalAlign: "top", height: 25}}
src={IconUrl + requirementBuildings[0].icon.replaceAll('\\', '/')}/>
&nbsp;{" "}<a href={`/mod/${building.modId}/race/${building.race.id}/building/${requirementBuildings[0].id}`}>
{requirementBuildings[0].name}
</a> or &nbsp;<img style={{verticalAlign: "top", height: 25}}
src={IconUrl + requirementBuildings[1].icon.replaceAll('\\', '/')}/>
&nbsp;{" "}<a href={`/mod/${building.modId}/race/${building.race.id}/building/${requirementBuildings[1].id}`}>
{requirementBuildings[1].name}</a></div>
);
}
function renderRequirementGlobalAddons(rgas: IBuildingAddonShort[], building: IBuilding) {
return <div> {rgas.map(rga =>
<span>&nbsp; Global addon: <img style={{verticalAlign: "top", height: 25}}
src={IconUrl + rga.icon.replaceAll('\\', '/')}/>
&nbsp;<a href={`/mod/${building.modId}/race/${building.race.id}/building/${rga.buildingId}#addon-${rga.id}`}>
{rga.name}
</a></span>
)}</div>
}
return <div className='addon-accordion' id={"addon-" + addon.id} ><Accordion>
<AccordionSummary
expandIcon={<ExpandMore/>}
aria-controls="panel1-content"
>
<span style={{fontSize: 20}}>
{addon.icon && <img className="sergeantIcon" src={IconUrl + addon.icon.replaceAll('\\', '/')}/>}
&nbsp; {addon.name}
</span>
</AccordionSummary>
<AccordionDetails>
<Grid2 container spacing={2}>
<Grid2 size={{xs: 12, md: 4}}>
<TableContainer component={Paper}>
<Table size="small" aria-label="a dense table">
<TableBody id="unit-stats-table">
<TableRow
sx={{'&:last-child td, &:last-child th': {border: 0}}}
>
<TableCell component="th" scope="row">Cost</TableCell>
<TableCell component="th" scope="row">
{addon.addonCostRequisition > 0 &&
<span>&nbsp;<img style={{verticalAlign: "top"}}
src="/images/Resource_requisition.gif"/>&nbsp;
{addon.addonCostRequisition.toFixed(0)}</span>}
{addon.addonCostPower > 0 && <span>&nbsp;<img style={{verticalAlign: "top"}}
src="/images/Resource_power.gif"/>&nbsp;
{addon.addonCostPower.toFixed(0)}</span>}
{(addon.addonCostPopulation !== undefined && addon.addonCostPopulation > 0) &&
<span>&nbsp;<img style={{verticalAlign: "top"}}
src="/images/Resource_orksquadcap.gif"/>&nbsp;
{addon.addonCostPopulation.toFixed(0)}</span>}
{(addon.addonCostFaith !== undefined && addon.addonCostFaith > 0) &&
<span>&nbsp;<img style={{verticalAlign: "top"}}
src="/images/Resource_faith.gif"/>&nbsp;
{addon.addonCostFaith}</span>}
{(addon.addonCostSouls !== undefined && addon.addonCostSouls > 0) &&
<span>&nbsp;<img style={{verticalAlign: "top"}}
src="/images/Resource_souls.gif"/>&nbsp;
{addon.addonCostSouls.toFixed(0)}</span>}
{(addon.addonCostTime !== undefined && addon.addonCostTime > 0) &&
<span>&nbsp;<AvTimerOutlinedIcon
style={{verticalAlign: "top", fontSize: "18px"}}/>&nbsp;
{addon.addonCostTime}s</span>}
</TableCell>
</TableRow>
</TableBody>
</Table>
</TableContainer><br/>
<AddonModifiersProvidesTable modifiers={addon.addonModifiers}/>
</Grid2>
<Grid2 size={{xs: 12, md: 8}}>
<div style={{whiteSpace: "pre-wrap"}}>
{addon.description}
</div>
</Grid2>
{addon.addonModifiers !== null &&
<Grid2 size={{xs: 12, md: 12}}>
<AddonModifiersProvidesWeapons modifiers={addon.addonModifiers} replacedAddonModifiers={prevAddonModifiers} weapons={building.weapons}/>
</Grid2>}
{addon.addonRequirement !== null &&
<Grid2 size={{xs: 12, md: 12}}>
<h4>Required: </h4>
{addon.addonRequirement.requiredTotalPop !== undefined && addon.addonRequirement.requiredTotalPop !== null &&
<div>&nbsp; Population: <img style={{verticalAlign: "top", height: 25}}
src="/images/Resource_orksquadcap.gif"/>&nbsp;
{addon.addonRequirement.requiredTotalPop}</div>
}
{addon.addonRequirement.requireAddon !== null &&
<div>&nbsp; Addon: <img style={{verticalAlign: "top", height: 25}}
src={IconUrl + addon.addonRequirement.requireAddon.icon.replaceAll('\\', '/')}/>&nbsp;
<a href={"#addon-" + addon.addonRequirement.requireAddon.id} onClick={() => goToAddon(`#addon-` + addon.addonRequirement.requireAddon.id)}>{addon.addonRequirement.requireAddon.name}</a>
{addon.addonRequirement.replaceWhenDone && <i> (old provides replace)</i>}
</div>
}
{addon.addonRequirement.requirementBuildings.map(b =>
<div>&nbsp; Building: <img style={{verticalAlign: "top", height: 25}}
src={IconUrl + b.icon.replaceAll('\\', '/')}/>&nbsp;
<a href= {'/mod/'+ building.modId +'/race/'+ building.race.id +'/building/' + b.id + "/"}>{b.name}</a></div>)
}
{addon.addonRequirement.requirementBuildingsEither.length !== 0 &&
renderRequirementBuilding(addon.addonRequirement.requirementBuildingsEither, building)}
{addon.addonRequirement.requirementsGlobalAddons.length !== 0 &&
renderRequirementGlobalAddons(addon.addonRequirement.requirementsGlobalAddons, building)}
</Grid2>}
</Grid2>
<i className="rgdFrom">{addon.filename}</i>
</AccordionDetails>
</Accordion></div>
}
export default BuildingAddon;

View File

@ -3,14 +3,8 @@
scroll-margin-top: 15px; scroll-margin-top: 15px;
} }
@-webkit-keyframes blink2 {
100% { color: rgba(34, 34, 34, 0); }
}
@keyframes blink2 {
100% { color: rgba(34, 34, 34, 0); }
}
.selected-addon div > h3 {
-webkit-animation: blink2 1s linear infinite; .selected-addon div {
animation: blink2 1s linear infinite; background-color: antiquewhite;
} }

View File

@ -1,29 +1,18 @@
import {AvailableBuildings, AvailableMods, AvailableUnits, IconUrl} from "../core/api"; import {AvailableBuildings, AvailableMods, IconUrl} from "../core/api";
import React, {MutableRefObject, useEffect, useRef} from "react"; import React 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'
import { import {Button, Grid2, Paper, Table, TableBody, TableCell, TableContainer, TableRow} from "@mui/material";
Accordion, import {ArrowBack} from "@mui/icons-material";
AccordionDetails,
AccordionSummary,
Button,
Grid2,
Paper,
Table,
TableBody,
TableCell,
TableContainer,
TableRow
} from "@mui/material";
import {ArrowBack, ExpandMore} 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";
import UnitsTable from "../classes/UnitsTable"; import UnitsTable from "../classes/UnitsTable";
import {IMod} from "../types/Imod"; import {IMod} from "../types/Imod";
import {IBuilding, IBuildingAddon, IBuildingAddonShort} from "../types/IBuilding"; import {IBuilding} from "../types/IBuilding";
import {IBuildingShort} from "../types/IBuildingShort"; import Vision from "../classes/Vision";
import BuildingAddon from "../classes/building/BuildingAddon";
interface UintPageState { interface UintPageState {
building: IBuilding, building: IBuilding,
@ -33,10 +22,6 @@ interface UintPageState {
function Building(building: IBuilding, mod: IMod) { function Building(building: IBuilding, mod: IMod) {
const detect = building.detectRadius > 0 ? <span>&nbsp;<img style={{verticalAlign: "top"}}
src="/images/DETECT_YES.webp"/> {building.detectRadius}</span> :
<span>&nbsp;<img style={{verticalAlign: "top"}}
src="/images/DETECT_NO.webp"/></span>
let mapBuildingWeapons: Map<number, Map<number, IWeapon>> = new Map(); let mapBuildingWeapons: Map<number, Map<number, IWeapon>> = new Map();
@ -53,117 +38,6 @@ function Building(building: IBuilding, mod: IMod) {
function BuildingAddon(addon: IBuildingAddon){
return <div className='addon-accordion' id={"addon-" + addon.id} ><Accordion>
<AccordionSummary
expandIcon={<ExpandMore/>}
aria-controls="panel1-content"
>
<span style={{fontSize: 20}}>
{addon.icon && <img className="sergeantIcon" src={IconUrl + addon.icon.replaceAll('\\', '/')}/>}
&nbsp; {addon.name}
</span>
</AccordionSummary>
<AccordionDetails>
<Grid2 container spacing={2}>
<Grid2 size={{xs: 12, md: 4}}>
<TableContainer component={Paper}>
<Table size="small" aria-label="a dense table">
<TableBody id="unit-stats-table">
<TableRow
sx={{'&:last-child td, &:last-child th': {border: 0}}}
>
<TableCell component="th" scope="row">Cost</TableCell>
<TableCell component="th" scope="row">
{addon.addonCostRequisition > 0 &&
<span>&nbsp;<img style={{verticalAlign: "top"}}
src="/images/Resource_requisition.gif"/>&nbsp;
{addon.addonCostRequisition.toFixed(0)}</span>}
{addon.addonCostPower > 0 && <span>&nbsp;<img style={{verticalAlign: "top"}}
src="/images/Resource_power.gif"/>&nbsp;
{addon.addonCostPower.toFixed(0)}</span>}
{(addon.addonCostPopulation !== undefined && addon.addonCostPopulation > 0) &&
<span>&nbsp;<img style={{verticalAlign: "top"}}
src="/images/Resource_orksquadcap.gif"/>&nbsp;
{addon.addonCostPopulation.toFixed(0)}</span>}
{(addon.addonCostFaith !== undefined && addon.addonCostFaith > 0) &&
<span>&nbsp;<img style={{verticalAlign: "top"}}
src="/images/Resource_faith.gif"/>&nbsp;
{addon.addonCostFaith}</span>}
{(addon.addonCostSouls !== undefined && addon.addonCostSouls > 0) &&
<span>&nbsp;<img style={{verticalAlign: "top"}}
src="/images/Resource_souls.gif"/>&nbsp;
{addon.addonCostSouls.toFixed(0)}</span>}
{(addon.addonCostTime !== undefined && addon.addonCostTime > 0) &&
<span>&nbsp;<AvTimerOutlinedIcon
style={{verticalAlign: "top", fontSize: "18px"}}/>&nbsp;
{addon.addonCostTime}s</span>}
</TableCell>
</TableRow>
</TableBody>
</Table>
</TableContainer>
</Grid2>
<Grid2 size={{xs: 12, md: 8}}>
<div style={{whiteSpace: "pre-wrap"}}>
{addon.description}
</div>
</Grid2>
{addon.addonRequirement !== null &&
<Grid2 size={{xs: 12, md: 12}}>
<h4>Required: </h4>
{addon.addonRequirement.requiredTotalPop !== undefined && addon.addonRequirement.requiredTotalPop !== null &&
<div>&nbsp; Population: <img style={{verticalAlign: "top", height: 25}}
src="/images/Resource_orksquadcap.gif"/>&nbsp;
{addon.addonRequirement.requiredTotalPop}</div>
}
{addon.addonRequirement.requireAddon !== null &&
<div>&nbsp; Addon: <img style={{verticalAlign: "top", height: 25}}
src={IconUrl + addon.addonRequirement.requireAddon.icon.replaceAll('\\', '/')}/>&nbsp;
<a href={"#addon-" + addon.addonRequirement.requireAddon.id} onClick={() => goToAddon(`#addon-` + addon.addonRequirement.requireAddon.id)}>{addon.addonRequirement.requireAddon.name}</a></div>
}
{addon.addonRequirement.requirementBuildings.map(b =>
<div>&nbsp; Building: <img style={{verticalAlign: "top", height: 25}}
src={IconUrl + b.icon.replaceAll('\\', '/')}/>&nbsp;
<a href= {'/mod/'+ building.modId +'/race/'+ building.race.id +'/building/' + b.id + "/"}>{b.name}</a></div>)
}
{addon.addonRequirement.requirementBuildingsEither.length !== 0 &&
renderRequirementBuilding(addon.addonRequirement.requirementBuildingsEither, building)}
{addon.addonRequirement.requirementsGlobalAddons.length !== 0 &&
renderRequirementGlobalAddons(addon.addonRequirement.requirementsGlobalAddons, building)}
</Grid2>}
</Grid2>
<i className="rgdFrom">{addon.filename}</i>
</AccordionDetails>
</Accordion></div>
}
function renderRequirementBuilding(requirementBuildings: IBuildingShort[], building: IBuilding) {
return requirementBuildings.length > 0 && (
<div>&nbsp; Buildings: <img style={{verticalAlign: "top", height: 25}}
src={IconUrl + requirementBuildings[0].icon.replaceAll('\\', '/')}/>
&nbsp;{" "}<a href={`/mod/${building.modId}/race/${building.race.id}/building/${requirementBuildings[0].id}`}>
{requirementBuildings[0].name}
</a> or &nbsp;<img style={{verticalAlign: "top", height: 25}}
src={IconUrl + requirementBuildings[1].icon.replaceAll('\\', '/')}/>
&nbsp;{" "}<a href={`/mod/${building.modId}/race/${building.race.id}/building/${requirementBuildings[1].id}`}>
{requirementBuildings[1].name}</a></div>
);
}
function renderRequirementGlobalAddons(rgas: IBuildingAddonShort[], building: IBuilding) {
return <div> {rgas.map(rga =>
<span>&nbsp; Global addon: <img style={{verticalAlign: "top", height: 25}}
src={IconUrl + rga.icon.replaceAll('\\', '/')}/>
&nbsp;<a href={`/mod/${building.modId}/race/${building.race.id}/building/${rga.buildingId}#addon-${rga.id}`}>
{rga.name}
</a></span>
)}</div>
}
return ( return (
<div> <div>
<h1>{mod.name} ({mod.version})</h1> <h1>{mod.name} ({mod.version})</h1>
@ -227,9 +101,9 @@ function Building(building: IBuilding, mod: IMod) {
<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">Detect</TableCell> <TableCell component="th" scope="row">Sight</TableCell>
<TableCell component="th" scope="row"> <TableCell component="th" scope="row">
{detect} <Vision sight={building.sightRadius} detect={building.detectRadius}/>
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow <TableRow
@ -252,13 +126,13 @@ function Building(building: IBuilding, mod: IMod) {
{building.addons.length > 0 && <Grid2 size={12}> {building.addons.length > 0 && <Grid2 size={12}>
<h3>Addons</h3> <h3>Addons</h3>
{building.addons.map(b => {building.addons.map(b =>
BuildingAddon(b) <BuildingAddon addon={b} building={building}/>
)} )}
</Grid2> } </Grid2> }
<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 unitWeapons={mapBuildingWeapons.get(h)} hardpoint={h}/>)} }).map(h => <WeaponSlot showOnlyDefault={true} unitWeapons={mapBuildingWeapons.get(h)} hardpoint={h}/>)}
</Grid2> </Grid2>
</Grid2> </Grid2>
<i className="rgdFrom">{building.filename}</i> <i className="rgdFrom">{building.filename}</i>
@ -312,4 +186,6 @@ class BuildingPage extends React.Component<any, UintPageState> {
} }
} }
export default withRouter(BuildingPage); export default withRouter(BuildingPage);
export { goToAddon };

View File

@ -23,6 +23,7 @@ import Sergeant from "../classes/Sergeant";
import WeaponSlot from "../classes/WeaponSlot"; 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";
interface UintPageState { interface UintPageState {
unit: IUnit, unit: IUnit,
@ -40,11 +41,6 @@ function Unit(unit: IUnit, mod: IMod) {
</span> : "-" </span> : "-"
const detect = unit.detectRadius > 0 ? <span>&nbsp;<img style={{verticalAlign: "top"}}
src="/images/DETECT_YES.webp"/> {unit.detectRadius}</span> :
<span>&nbsp;<img style={{verticalAlign: "top"}}
src="/images/DETECT_NO.webp"/></span>
let mapWithUnitWeapons: Map<number, Map<number, IWeapon>> = new Map(); let mapWithUnitWeapons: Map<number, Map<number, IWeapon>> = new Map();
unit.weapons.forEach(weapon => { unit.weapons.forEach(weapon => {
@ -214,12 +210,12 @@ function Unit(unit: IUnit, mod: IMod) {
<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">Detect</TableCell> <TableCell component="th" scope="row">Vision</TableCell>
<TableCell component="th" scope="row"> <TableCell component="th" scope="row">
{detect} <Vision sight={unit.sightRadius} detect={unit.detectRadius}/>
</TableCell> </TableCell>
</TableRow> </TableRow>
{unit.repairMax !== undefined && {unit.repairMax !== undefined && unit.repairMax !== null &&
<TableRow> <TableRow>
<TableCell>Repair max</TableCell> <TableCell>Repair max</TableCell>
<TableCell> <TableCell>

View File

@ -55,6 +55,7 @@ export interface IAddonRequirement {
requirementBuildings: IBuildingShort[]; requirementBuildings: IBuildingShort[];
requirementBuildingsEither: IBuildingShort[]; requirementBuildingsEither: IBuildingShort[];
requirementsGlobalAddons: IBuildingAddonShort[]; requirementsGlobalAddons: IBuildingAddonShort[];
replaceWhenDone: Boolean;
requireAddon: IBuildingAddonShort; requireAddon: IBuildingAddonShort;
requiredTotalPop?: number; requiredTotalPop?: number;
} }

View File

@ -10,5 +10,5 @@ export interface IBuildingShort {
icon: string icon: string
id: number id: number
canDetect: boolean canDetect: boolean
armourTypeName: string armorTypeName: string
} }