- Add death explosions info

- Add mob bonus info
- Reworked abilities, add child objects
- Add unit morale break behaviour
- Rework UA mod frontend
This commit is contained in:
anibus 2026-03-14 15:05:45 +03:00
parent e0fe94b8ca
commit 9d4bb49713
23 changed files with 882 additions and 266 deletions

2
.env
View File

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

BIN
public/images/Mob_bonus.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 B

View File

@ -7,8 +7,9 @@
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<meta <meta
name="description" name="description"
content="Autogeneration wiki" content="Dawn of War wiki. Unification mod wiki. Unification mod unit stats. Supported all popular mods."
/> />
<meta name="google-site-verification" content="Q4XMn2UDpL2xmK7iBfaWQpVN8EPy8oGxN-7HqSKapb0" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!-- <!--
manifest.json provides metadata used when your web app is installed on a manifest.json provides metadata used when your web app is installed on a
@ -24,7 +25,7 @@
work correctly both with client-side routing and a non-root public URL. work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`. Learn how to configure a non-root public URL by running `npm run build`.
--> -->
<title>Wiki Soulstorm</title> <title>Dawn of War Wiki</title>
</head> </head>
<body> <body>
<!-- Yandex.Metrika counter --> <script type="text/javascript" > (function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)}; m[i].l=1*new Date(); for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }} k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)}) (window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym"); ym(99502794, "init", { clickmap:true, trackLinks:true, accurateTrackBounce:true, webvisor:true }); </script> <noscript><div><img src="https://mc.yandex.ru/watch/99502794" style="position:absolute; left:-9999px;" alt="" /></div></noscript> <!-- /Yandex.Metrika counter --> <!-- Yandex.Metrika counter --> <script type="text/javascript" > (function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)}; m[i].l=1*new Date(); for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }} k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)}) (window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym"); ym(99502794, "init", { clickmap:true, trackLinks:true, accurateTrackBounce:true, webvisor:true }); </script> <noscript><div><img src="https://mc.yandex.ru/watch/99502794" style="position:absolute; left:-9999px;" alt="" /></div></noscript> <!-- /Yandex.Metrika counter -->

View File

@ -25,6 +25,8 @@ import {ModifiersProvidesTable} from "./ModifiersProvideTable";
import {IAbilityFill, IAbilityShort} from "../types/IAbility"; import {IAbilityFill, IAbilityShort} from "../types/IAbility";
import AvTimerOutlinedIcon from "@mui/icons-material/AvTimer"; import AvTimerOutlinedIcon from "@mui/icons-material/AvTimer";
import ability from "./Ability"; import ability from "./Ability";
import AbilitySpawnedObject from "./AbilitySpawnedObject";
import DpsTable from "./DpsTable";
interface IAbilityFullState { interface IAbilityFullState {
ability?: IAbilityFill; ability?: IAbilityFill;
@ -37,8 +39,6 @@ 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: "rgb(244,244,244)", backgroundColor: "rgb(244,244,244)",
@ -80,64 +80,14 @@ export default function AbilityFull(props: { abilityId?: number, mod: IMod, race
const ability = abilityFull.ability const ability = abilityFull.ability
function getPiercingK(armorType: string): number|null {
if(ability.targetFilter.length > 0 && ability.targetFilter.find(tf => tf.name == armorType) === undefined) return null function isAbilityApplyTo(armorType: string) {
const abilityPiercing = ability.piercings.find((p) => p.armorType.name === armorType) return (ability.targetFilter.length === 0 || ability.targetFilter.find(tf => tf.name == armorType)) !== undefined ? <span></span> : <span>-</span>
return (typeof abilityPiercing !== "undefined" ? abilityPiercing.piercingValue : 10) / 100
} }
const infLowPiercing = getPiercingK(ArmorTypeNames.InfantryLow) const showDpsTable = (ability.minDamage !== undefined && ability.minDamage > 0 || ability.moraleDamage !== undefined && ability.moraleDamage > 0)
const infMedPiercing = getPiercingK(ArmorTypeNames.InfantryMedium)
const infHighPiercing = getPiercingK(ArmorTypeNames.InfantryHigh)
const infHeavyMedPiercing = getPiercingK(ArmorTypeNames.InfantryHeavyMedium)
const infHeavyHighPiercing = getPiercingK(ArmorTypeNames.InfantryHeavyHigh)
const demonPiercing = getPiercingK(ArmorTypeNames.DemonMedium)
const demonHighPiercing = getPiercingK(ArmorTypeNames.DemonHigh)
const commanderPiercing = getPiercingK(ArmorTypeNames.Commander)
const airPiercing = getPiercingK(ArmorTypeNames.Air)
const vehLowPiercing = getPiercingK(ArmorTypeNames.VehicleLow)
const vehMedPiercing = getPiercingK(ArmorTypeNames.VehicleMedium)
const vehHighPiercing = getPiercingK(ArmorTypeNames.VehicleHigh)
const buildingLowPiercing = getPiercingK(ArmorTypeNames.BuildingLow)
const buildingMedPiercing = getPiercingK(ArmorTypeNames.BuildingMedium)
const buildingHighPiercing = getPiercingK(ArmorTypeNames.BuildingHigh)
// UA mod
const demonLowPiercing = getPiercingK(ArmorTypeNames.DemonLow)
const buildingSuperPiercing = getPiercingK(ArmorTypeNames.BuildingSuper)
const livingMetalPiercing = getPiercingK(ArmorTypeNames.LivingMetal)
const titanPiercing = getPiercingK(ArmorTypeNames.Titan)
const getTotalDamage = (damagePiercing: number|null) => {
if(damagePiercing === null) return ""
if(ability.minDamageValue !== undefined && ability.minDamage !== undefined && ability.maxDamage !== undefined){
var minDamage = damagePiercing * ability.minDamage
var maxDamage = damagePiercing * ability.maxDamage
if(ability.minDamageValue !== undefined){
if (minDamage < ability.minDamageValue) {
minDamage = ability.minDamageValue
}
if (maxDamage < ability.minDamageValue) {
maxDamage = ability.minDamageValue
}
}
const averageDmg = (minDamage + maxDamage) / 2
return averageDmg.toFixed(2)
}
}
const getMoraleDamage = () => {
if(ability.moraleDamage !== undefined) return (ability.moraleDamage / 2).toFixed(2)
}
const showTargetTable = !showDpsTable && ability.abilityEnvironment == null && (ability.targetFilter.length > 0 || ability.radius !== 0)
return ( return (
<div> <div>
@ -189,7 +139,7 @@ export default function AbilityFull(props: { abilityId?: number, mod: IMod, race
<TableCell component="th" scope="row"> <TableCell component="th" scope="row">
<img style={{verticalAlign: "top"}} <img style={{verticalAlign: "top"}}
src="/images/Time_icon.webp"/>&nbsp; src="/images/Time_icon.webp"/>&nbsp;
{ability.rechargeTime.toFixed(0)}s&nbsp; {ability.rechargeTime}s&nbsp;
{ability.rechargeTimerGlobal && <i style={{fontSize: 10}}>global cooldown</i>} {ability.rechargeTimerGlobal && <i style={{fontSize: 10}}>global cooldown</i>}
</TableCell> </TableCell>
</TableRow> </TableRow>
@ -251,12 +201,16 @@ export default function AbilityFull(props: { abilityId?: number, mod: IMod, race
{props.isChild !== true && ability.description} {props.isChild !== true && ability.description}
</div> </div>
</Grid2> </Grid2>
{(ability.minDamage !== undefined && ability.minDamage > 0 || ability.moraleDamage !== undefined && ability.moraleDamage > 0) && {showDpsTable ?
<Grid2 size={12}> <Grid2 size={12}>
{(ability.refreshTime !== undefined && ability.durationTime !== undefined && ability.refreshTime * 2 < ability.durationTime) && <i>Every <b>{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}
/>
</Grid2> : showTargetTable ?
<Grid2 size={12}>
<TableContainer> <TableContainer>
{ props.mod !== undefined && props.mod.name.includes("Ultimate Apocalypse") ? { props.mod !== undefined && props.mod.technicalName === 'UltimateApocalypse' ?
<Table sx={{marginTop: "10px", textAlign: "center"}} size="small" aria-label="a dense table"> <Table sx={{ textAlign: "center"}} size="small" aria-label="a dense table">
<TableHead> <TableHead>
<TableRow> <TableRow>
<StyledTableCell><ArmorType <StyledTableCell><ArmorType
@ -282,16 +236,16 @@ export default function AbilityFull(props: { abilityId?: number, mod: IMod, race
</TableHead> </TableHead>
<TableBody> <TableBody>
<TableRow> <TableRow>
<StyledTableCell>{getTotalDamage(infLowPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.InfantryLow)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(infMedPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.InfantryMedium)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(infHighPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.InfantryHigh)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(infHeavyMedPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.InfantryHeavyMedium)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(infHeavyHighPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.InfantryHeavyHigh)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(commanderPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.Commander)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(demonLowPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.DemonLow)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(demonPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.DemonMedium)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(demonHighPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.DemonHigh)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(airPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.Air)}</StyledTableCell>
</TableRow> </TableRow>
</TableBody> </TableBody>
<TableHead> <TableHead>
@ -314,29 +268,25 @@ export default function AbilityFull(props: { abilityId?: number, mod: IMod, race
name={ArmorTypeNames.BuildingHigh}/></StyledTableCell> name={ArmorTypeNames.BuildingHigh}/></StyledTableCell>
<StyledTableCell><ArmorType <StyledTableCell><ArmorType
name={ArmorTypeNames.BuildingSuper}/></StyledTableCell> name={ArmorTypeNames.BuildingSuper}/></StyledTableCell>
<StyledTableCell><img style={{verticalAlign: "top"}} <StyledTableCell></StyledTableCell>
src="/images/ARM_Morale.webp"/>
<div style={{width: 20, fontSize: 12, height: 50}}>
<i>Morale</i></div>
</StyledTableCell>
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
<TableRow> <TableRow>
<StyledTableCell>{getTotalDamage(vehLowPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.VehicleLow)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(vehMedPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.VehicleMedium)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(vehHighPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.VehicleHigh)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(livingMetalPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.LivingMetal)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(titanPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.Titan)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(buildingLowPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.BuildingLow)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(buildingMedPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.BuildingMedium)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(buildingHighPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.BuildingHigh)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(buildingSuperPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.BuildingSuper)}</StyledTableCell>
<StyledTableCell>{getMoraleDamage()}</StyledTableCell> <StyledTableCell></StyledTableCell>
</TableRow> </TableRow>
</TableBody> </TableBody>
</Table> : </Table> :
<Table sx={{marginTop: "10px"}} size="small" aria-label="a dense table"> <Table size="small" aria-label="a dense table">
<TableHead> <TableHead>
<TableRow> <TableRow>
<StyledTableCell><ArmorType <StyledTableCell><ArmorType
@ -368,41 +318,34 @@ export default function AbilityFull(props: { abilityId?: number, mod: IMod, race
name={ArmorTypeNames.BuildingMedium}/></StyledTableCell> name={ArmorTypeNames.BuildingMedium}/></StyledTableCell>
<StyledTableCell><ArmorType <StyledTableCell><ArmorType
name={ArmorTypeNames.BuildingHigh}/></StyledTableCell> name={ArmorTypeNames.BuildingHigh}/></StyledTableCell>
<StyledTableCell><img style={{verticalAlign: "top"}}
src="/images/ARM_Morale.webp"/>
<div style={{width: 20, fontSize: 12, height: 50}}>
<i>Morale</i></div>
</StyledTableCell>
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
<TableRow> <TableRow>
<StyledTableCell>{getTotalDamage(infLowPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.InfantryLow)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(infMedPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.InfantryMedium)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(infHighPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.InfantryHigh)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(infHeavyMedPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.InfantryHeavyMedium)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(infHeavyHighPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.InfantryHeavyHigh)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(commanderPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.Commander)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(demonPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.DemonMedium)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(demonHighPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.DemonHigh)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(airPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.Air)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(vehLowPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.VehicleLow)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(vehMedPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.VehicleMedium)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(vehHighPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.VehicleHigh)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(buildingLowPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.BuildingLow)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(buildingMedPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.BuildingMedium)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(buildingHighPiercing)}</StyledTableCell> <StyledTableCell>{isAbilityApplyTo(ArmorTypeNames.BuildingHigh)}</StyledTableCell>
<StyledTableCell>{getMoraleDamage()}</StyledTableCell>
</TableRow> </TableRow>
</TableBody> </TableBody>
</Table> </Table>
} }
</TableContainer> </TableContainer>
</Grid2>} </Grid2> : <span></span>}
<ModifiersProvidesTable modifiers={ability.modifiers} affectedData={ability.affectedData} modId={props.mod.id} race={props.race}/> <ModifiersProvidesTable modifiers={ability.modifiers} affectedData={ability.affectedData} modId={props.mod.id} race={props.race}/>
{/*TODO: spawnedEntityName not parsing correctly, fix it*/}
{ability.spawnedEntityName !== undefined && ability.spawnedEntityName !== null && <span>Spawn {ability.spawnedEntityName}</span>}
</Grid2> </Grid2>
{(ability.abilityEnvironment != null) && <AbilitySpawnedObject abilityEnvironment={ability.abilityEnvironment} race={props.race} mod={props.mod}/>}
{ability.childAbility !== undefined && ability.childAbility !== null && <AbilityFull {ability.childAbility !== undefined && ability.childAbility !== null && <AbilityFull
abilityFull={ability.childAbility} isChild={true} mod={props.mod} race={props.race}/>} abilityFull={ability.childAbility} isChild={true} mod={props.mod} race={props.race}/>}
{props.isChild !== true && ability.requirements !== undefined && ability.requirements !== null && {props.isChild !== true && ability.requirements !== undefined && ability.requirements !== null &&

View File

@ -0,0 +1,135 @@
import {
Accordion,
AccordionDetails,
AccordionSummary, Grid2, Paper,
Table,
TableBody,
TableCell, TableContainer,
TableRow,
Tooltip
} from "@mui/material";
import {ExpandMore} from "@mui/icons-material";
import React from "react";
import {IAbilityShort} from "../types/IAbility";
import {getIcon} from "./ModifiersProvideTable";
import {IMod} from "../types/Imod";
import AbilityFull from "./AbilityFull";
import {Irace} from "../types/Irace";
import {IAbilityEnvironment} from "../types/IAbilityEnvironment";
import AvTimerOutlinedIcon from "@mui/icons-material/AvTimer";
import ArmorType from "./ArmorType";
import Vision from "./Vision";
import Ability from "./Ability";
import DeathExplosion from "./DeathExplosion";
interface AbilityEnvironmentProps {
abilityEnvironment: IAbilityEnvironment,
race: Irace,
mod: IMod,
}
function AbilitySpawnedObject(props: AbilityEnvironmentProps) {
const abilityEnvironment = props.abilityEnvironment
return <div>
<h3> {props.abilityEnvironment.name ?? props.abilityEnvironment.filename.charAt(0).toUpperCase() + props.abilityEnvironment.filename.slice(1).replaceAll('_', ' ').replace('.rgd', '')}
<i style={{fontSize: 11}}> (Spawned object)</i>
</h3>
<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">
{abilityEnvironment.armorType !== null &&
<TableRow
sx={{'&:last-child td, &:last-child th': {border: 0}}}
>
<TableCell component="th" scope="row">Armor type</TableCell>
<TableCell component="th" scope="row">
{abilityEnvironment.armorType2 == null ?
<ArmorType name={abilityEnvironment.armorType.name} compact={false}/> :
<Tooltip
title={"upgrade/debuff can turns to " + abilityEnvironment.armorType2.name}><span><ArmorType
name={abilityEnvironment.armorType.name}
compact={false}/></span></Tooltip>}
</TableCell>
</TableRow>
}
{abilityEnvironment.health !== null &&
<TableRow
sx={{'&:last-child td, &:last-child th': {border: 0}}}
>
<TableCell component="th" scope="row">Health</TableCell>
<TableCell component="th" scope="row">
<img style={{verticalAlign: "top"}}
src="/images/Health_icon.webp"/>&nbsp;
{abilityEnvironment.health} {abilityEnvironment.healthRegeneration != null && abilityEnvironment.healthRegeneration > 0 &&
<span>+{abilityEnvironment.healthRegeneration}/s</span>}
{abilityEnvironment.armour !== undefined && abilityEnvironment.armour !== 0 &&
<span><img style={{height: 20, verticalAlign: "top"}}
src="/images/defence.png"/>{abilityEnvironment.armour} </span>}
</TableCell>
</TableRow>
}
{abilityEnvironment.moveSpeed != null &&
<TableRow
sx={{'&:last-child td, &:last-child th': {border: 0}}}
>
<TableCell component="th" scope="row">Move speed</TableCell>
<TableCell component="th" scope="row">
{abilityEnvironment.moveSpeed}
</TableCell>
</TableRow>
}
{abilityEnvironment.sightRadius != null &&
<TableRow
sx={{'&:last-child td, &:last-child th': {border: 0}}}
>
<TableCell component="th" scope="row">Vision</TableCell>
<TableCell component="th" scope="row">
<Vision sight={abilityEnvironment.sightRadius ?? 0}
detect={abilityEnvironment.detectRadius ?? 0}/>
</TableCell>
</TableRow>
}
{abilityEnvironment.lifetime != null &&
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
<TableCell component="th" scope="row">Lifetime</TableCell>
<TableCell component="th" scope="row">
<img style={{verticalAlign: "top"}}
src="/images/Time_icon.webp"/>&nbsp;
{abilityEnvironment.lifetime.toFixed(0)}s&nbsp;
</TableCell>
</TableRow>
}
</TableBody>
</Table>
</TableContainer>
</Grid2>
<Grid2 size={{xs: 12, md: 8}}>
<div style={{whiteSpace: "pre-wrap"}}>
{abilityEnvironment.description}
</div>
</Grid2>
{abilityEnvironment.abilities.length > 0 && <Grid2 size={12}>
{abilityEnvironment.abilities.map(a =>
<Ability mod={props.mod} ability={a} race={props.race}/>
)}
</Grid2>}
{abilityEnvironment.deathExplosions.length > 0 &&
<Grid2 size={12}>
{abilityEnvironment.deathExplosions.map(da =>
<DeathExplosion deathExplosion={da} mod={props.mod}/>
)}
</Grid2>
}
</Grid2>
</div>
}
export default AbilitySpawnedObject;

View File

@ -61,7 +61,7 @@ class ArmorType extends React.Component<IArmorType, any> {
render() { render() {
if(this.props.compact){ if(this.props.compact){
return (<span> {this.props.compact ? return (<span> {this.props.compact ?
<div style={{ fontSize: 12, width: 40, textAlign: "center"}}><img src={this.renderArmorImage(this.props.name)}/><i>{this.props.name}</i> <div style={{ fontSize: 12, textAlign: "center"}}><img src={this.renderArmorImage(this.props.name)}/><br/><i>{this.props.name}</i>
</div> : </div> :
<span><img src={this.renderArmorImage(this.props.name)}/> {this.props.name}</span>} </span>); <span><img src={this.renderArmorImage(this.props.name)}/> {this.props.name}</span>} </span>);
} else } else

View File

@ -0,0 +1,97 @@
import {
Accordion,
AccordionDetails,
AccordionSummary, Grid2, Paper,
Table,
TableBody,
TableCell, TableContainer, TableHead,
TableRow,
Tooltip
} from "@mui/material";
import {ExpandMore} from "@mui/icons-material";
import React from "react";
import {IAbilityShort} from "../types/IAbility";
import {getIcon, ModifiersProvidesTable} from "./ModifiersProvideTable";
import {IMod} from "../types/Imod";
import AbilityFull from "./AbilityFull";
import {Irace} from "../types/Irace";
import {IAbilityEnvironment} from "../types/IAbilityEnvironment";
import AvTimerOutlinedIcon from "@mui/icons-material/AvTimer";
import ArmorType from "./ArmorType";
import Vision from "./Vision";
import Ability from "./Ability";
import {IDeathExplosion} from "../types/IDeathExplosion";
import Required from "./Required";
import ArmorTypeNames from "../types/ArmorTypeValues";
import DpsTable from "./DpsTable";
interface DeathExpProps {
deathExplosion: IDeathExplosion,
mod: IMod,
}
function DeathExplosion(props: DeathExpProps) {
const deathExplosion = props.deathExplosion
const chanceTotalNotZero = deathExplosion.globalChance * deathExplosion.chance != 0
return chanceTotalNotZero ?
<div className='addon-research-accordion' id='death-explosion'><Accordion>
<AccordionSummary
expandIcon={<ExpandMore/>}
aria-controls="panel1-content"
>
<span style={{fontSize: 20}}>
Death Explosion
</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">Chance</TableCell>
<TableCell component="th" scope="row">
{deathExplosion.globalChance * deathExplosion.chance}%
</TableCell>
</TableRow>
<TableRow
sx={{'&:last-child td, &:last-child th': {border: 0}}}
>
<TableCell component="th" scope="row">Damage radius</TableCell>
<TableCell component="th" scope="row">
{deathExplosion.damageRadius}
</TableCell>
</TableRow>
<TableRow
sx={{'&:last-child td, &:last-child th': {border: 0}}}
>
<TableCell component="th" scope="row">Throw force</TableCell>
<TableCell component="th" scope="row">
{deathExplosion.throwForceMin} - {deathExplosion.throwForceMax}
</TableCell>
</TableRow>
</TableBody>
</Table>
</TableContainer>
</Grid2>
<Grid2>
<DpsTable mod={props.mod} piercings={deathExplosion.armorPiercing} targetFilter={[]}
minDamageValue={deathExplosion.minDamageValue}
minDamage={deathExplosion.minDamage} maxDamage={deathExplosion.maxDamage}
moraleDamage={deathExplosion.moraleDamage}/>
</Grid2>
</Grid2>
</AccordionDetails>
</Accordion></div> : <span></span>
}
export default DeathExplosion;

238
src/classes/DpsTable.tsx Normal file
View File

@ -0,0 +1,238 @@
import React from "react";
import ArmorTypeNames from "../types/ArmorTypeValues";
import {
styled,
Table,
TableBody,
TableCell,
tableCellClasses,
TableContainer,
TableHead,
TableRow
} from "@mui/material";
import ArmorType from "./ArmorType";
import {IMod} from "../types/Imod";
import {IPiercing} from "../types/IPiercing";
import {IArmorType} from "../types/IArmorType";
export default function DpsTable(props: { mod: IMod, minDamageValue?: number, minDamage?: number, maxDamage?: number, piercings: IPiercing[], targetFilter: IArmorType[], moraleDamage?: number }) {
const StyledTableCell = styled(TableCell)(({theme}) => ({
[`&.${tableCellClasses.head}`]: {
backgroundColor: "rgb(244,244,244)",
marginRight: 'auto',
marginLeft: 'auto',
paddingLeft: 10
},
[`&.${tableCellClasses.body}`]: {
fontSize: 12,
textAlign: 'center',
paddingRight: 18,
paddingLeft: 10
},
}));
function getPiercingK(armorType: string): number|null {
if(props.targetFilter.length > 0 && props.targetFilter.find(tf => tf.name == armorType) === undefined) return null
const piercing = props.piercings.find((p) => p.armorType.name === armorType)
return (typeof piercing !== "undefined" ? piercing.piercingValue : 10) / 100
}
const infLowPiercing = getPiercingK(ArmorTypeNames.InfantryLow)
const infMedPiercing = getPiercingK(ArmorTypeNames.InfantryMedium)
const infHighPiercing = getPiercingK(ArmorTypeNames.InfantryHigh)
const infHeavyMedPiercing = getPiercingK(ArmorTypeNames.InfantryHeavyMedium)
const infHeavyHighPiercing = getPiercingK(ArmorTypeNames.InfantryHeavyHigh)
const demonPiercing = getPiercingK(ArmorTypeNames.DemonMedium)
const demonHighPiercing = getPiercingK(ArmorTypeNames.DemonHigh)
const commanderPiercing = getPiercingK(ArmorTypeNames.Commander)
const airPiercing = getPiercingK(ArmorTypeNames.Air)
const vehLowPiercing = getPiercingK(ArmorTypeNames.VehicleLow)
const vehMedPiercing = getPiercingK(ArmorTypeNames.VehicleMedium)
const vehHighPiercing = getPiercingK(ArmorTypeNames.VehicleHigh)
const buildingLowPiercing = getPiercingK(ArmorTypeNames.BuildingLow)
const buildingMedPiercing = getPiercingK(ArmorTypeNames.BuildingMedium)
const buildingHighPiercing = getPiercingK(ArmorTypeNames.BuildingHigh)
// UA mod
const demonLowPiercing = getPiercingK(ArmorTypeNames.DemonLow)
const buildingSuperPiercing = getPiercingK(ArmorTypeNames.BuildingSuper)
const livingMetalPiercing = getPiercingK(ArmorTypeNames.LivingMetal)
const titanPiercing = getPiercingK(ArmorTypeNames.Titan)
const getTotalDamage = (damagePiercing: number|null) => {
if(damagePiercing === null) return ""
if(props.minDamageValue !== undefined && props.minDamage !== undefined && props.maxDamage !== undefined){
var minDamage = damagePiercing * props.minDamage
var maxDamage = damagePiercing * props.maxDamage
if(props.minDamageValue !== undefined){
if (minDamage < props.minDamageValue) {
minDamage = props.minDamageValue
}
if (maxDamage < props.minDamageValue) {
maxDamage = props.minDamageValue
}
}
const averageDmg = (minDamage + maxDamage) / 2
return averageDmg.toFixed(2)
}
}
const getMoraleDamage = () => {
if(props.moraleDamage !== undefined) return (props.moraleDamage / 2).toFixed(2)
}
return (
<TableContainer>
{ props.mod !== undefined && props.mod.name.includes("Ultimate Apocalypse") ?
<Table sx={{ textAlign: "center"}} size="small" aria-label="a dense table">
<TableHead>
<TableRow>
<StyledTableCell><ArmorType
name={ArmorTypeNames.InfantryLow}/></StyledTableCell>
<StyledTableCell><ArmorType
name={ArmorTypeNames.InfantryMedium}/></StyledTableCell>
<StyledTableCell><ArmorType
name={ArmorTypeNames.InfantryHigh}/></StyledTableCell>
<StyledTableCell><ArmorType
name={ArmorTypeNames.InfantryHeavyMedium}/></StyledTableCell>
<StyledTableCell><ArmorType
name={ArmorTypeNames.InfantryHeavyHigh}/></StyledTableCell>
<StyledTableCell><ArmorType
name={ArmorTypeNames.Commander}/></StyledTableCell>
<StyledTableCell><ArmorType
name={ArmorTypeNames.DemonLow}/></StyledTableCell>
<StyledTableCell><ArmorType
name={ArmorTypeNames.DemonMedium}/></StyledTableCell>
<StyledTableCell><ArmorType
name={ArmorTypeNames.DemonHigh}/></StyledTableCell>
<StyledTableCell><ArmorType name={ArmorTypeNames.Air}/></StyledTableCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<StyledTableCell>{getTotalDamage(infLowPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(infMedPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(infHighPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(infHeavyMedPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(infHeavyHighPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(commanderPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(demonLowPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(demonPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(demonHighPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(airPiercing)}</StyledTableCell>
</TableRow>
</TableBody>
<TableHead>
<TableRow>
<StyledTableCell><ArmorType
name={ArmorTypeNames.VehicleLow}/></StyledTableCell>
<StyledTableCell><ArmorType
name={ArmorTypeNames.VehicleMedium}/></StyledTableCell>
<StyledTableCell><ArmorType
name={ArmorTypeNames.VehicleHigh}/></StyledTableCell>
<StyledTableCell><ArmorType
name={ArmorTypeNames.LivingMetal}/></StyledTableCell>
<StyledTableCell><ArmorType
name={ArmorTypeNames.Titan}/></StyledTableCell>
<StyledTableCell><ArmorType
name={ArmorTypeNames.BuildingLow}/></StyledTableCell>
<StyledTableCell><ArmorType
name={ArmorTypeNames.BuildingMedium}/></StyledTableCell>
<StyledTableCell><ArmorType
name={ArmorTypeNames.BuildingHigh}/></StyledTableCell>
<StyledTableCell><ArmorType
name={ArmorTypeNames.BuildingSuper}/></StyledTableCell>
<StyledTableCell><img style={{verticalAlign: "top"}}
src="/images/ARM_Morale.webp"/>
<div style={{width: 20, fontSize: 12, height: 50}}>
<i>Morale</i></div>
</StyledTableCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<StyledTableCell>{getTotalDamage(vehLowPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(vehMedPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(vehHighPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(livingMetalPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(titanPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(buildingLowPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(buildingMedPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(buildingHighPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(buildingSuperPiercing)}</StyledTableCell>
<StyledTableCell>{getMoraleDamage()}</StyledTableCell>
</TableRow>
</TableBody>
</Table> :
<Table size="small" aria-label="a dense table">
<TableHead>
<TableRow>
<StyledTableCell><ArmorType
name={ArmorTypeNames.InfantryLow}/></StyledTableCell>
<StyledTableCell><ArmorType
name={ArmorTypeNames.InfantryMedium}/></StyledTableCell>
<StyledTableCell><ArmorType
name={ArmorTypeNames.InfantryHigh}/></StyledTableCell>
<StyledTableCell><ArmorType
name={ArmorTypeNames.InfantryHeavyMedium}/></StyledTableCell>
<StyledTableCell><ArmorType
name={ArmorTypeNames.InfantryHeavyHigh}/></StyledTableCell>
<StyledTableCell><ArmorType
name={ArmorTypeNames.Commander}/></StyledTableCell>
<StyledTableCell><ArmorType
name={ArmorTypeNames.DemonMedium}/></StyledTableCell>
<StyledTableCell><ArmorType
name={ArmorTypeNames.DemonHigh}/></StyledTableCell>
<StyledTableCell><ArmorType name={ArmorTypeNames.Air}/></StyledTableCell>
<StyledTableCell><ArmorType
name={ArmorTypeNames.VehicleLow}/></StyledTableCell>
<StyledTableCell><ArmorType
name={ArmorTypeNames.VehicleMedium}/></StyledTableCell>
<StyledTableCell><ArmorType
name={ArmorTypeNames.VehicleHigh}/></StyledTableCell>
<StyledTableCell><ArmorType
name={ArmorTypeNames.BuildingLow}/></StyledTableCell>
<StyledTableCell><ArmorType
name={ArmorTypeNames.BuildingMedium}/></StyledTableCell>
<StyledTableCell><ArmorType
name={ArmorTypeNames.BuildingHigh}/></StyledTableCell>
<StyledTableCell><img style={{verticalAlign: "top"}}
src="/images/ARM_Morale.webp"/>
<div style={{width: 20, fontSize: 12, height: 50}}>
<i>Morale</i></div>
</StyledTableCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<StyledTableCell>{getTotalDamage(infLowPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(infMedPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(infHighPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(infHeavyMedPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(infHeavyHighPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(commanderPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(demonPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(demonHighPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(airPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(vehLowPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(vehMedPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(vehHighPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(buildingLowPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(buildingMedPiercing)}</StyledTableCell>
<StyledTableCell>{getTotalDamage(buildingHighPiercing)}</StyledTableCell>
<StyledTableCell>{getMoraleDamage()}</StyledTableCell>
</TableRow>
</TableBody>
</Table>
}
</TableContainer>
)
}

View File

@ -35,7 +35,8 @@ function getModName(mt: String){
case 'modifiers\\holy_icon_cost_power.lua': case 'modifiers\\holy_icon_cost_power.lua':
return <span>Next icon cost <img style={{verticalAlign: "top"}} src='/images/Resource_power.gif'/></span>; return <span>Next icon cost <img style={{verticalAlign: "top"}} src='/images/Resource_power.gif'/></span>;
case 'modifiers\\holy_icon_cost_requisition.lua': case 'modifiers\\holy_icon_cost_requisition.lua':
return <span>Next icon cost <img style={{verticalAlign: "top"}} src='/images/Resource_requisition.gif'/></span>; return <span>Next icon cost <img style={{verticalAlign: "top"}}
src='/images/Resource_requisition.gif'/></span>;
case 'modifiers\\enable_hardpoint_02.lua': case 'modifiers\\enable_hardpoint_02.lua':
return 'Weapon slot 2'; return 'Weapon slot 2';
case 'modifiers\\default_weapon_modifier_hardpoint1.lua': case 'modifiers\\default_weapon_modifier_hardpoint1.lua':
@ -68,6 +69,10 @@ function getModName(mt: String){
return 'Power cost'; return 'Power cost';
case 'modifiers\\cost_time_modifier.lua': case 'modifiers\\cost_time_modifier.lua':
return 'Cost time'; return 'Cost time';
case 'modifiers\\income_requisition_player_modifier.lua':
return 'Global income requisition';
case 'modifiers\\income_power_player_modifier.lua':
return 'Global income power';
default: default:
return mt.replace("modifiers\\", "").replace("modifier.lua", "").replace(".lua", "").replaceAll("_", " "); return mt.replace("modifiers\\", "").replace("modifier.lua", "").replace(".lua", "").replaceAll("_", " ");
} }
@ -99,6 +104,10 @@ function getModIcon(mt: String){
return <img style={{verticalAlign: "top"}} src='/images/Resource_cap_infantry.gif'/>; return <img style={{verticalAlign: "top"}} src='/images/Resource_cap_infantry.gif'/>;
case 'modifiers\\population_cap_player_modifier.lua': case 'modifiers\\population_cap_player_modifier.lua':
return <img style={{verticalAlign: "top"}} src='/images/Resource_orksquadcap.gif'/>; return <img style={{verticalAlign: "top"}} src='/images/Resource_orksquadcap.gif'/>;
case 'modifiers\\income_requisition_player_modifier.lua':
return <img style={{verticalAlign: "top"}} src='/images/Resource_requisition.gif'/>;
case 'modifiers\\income_power_player_modifier.lua':
return <img style={{verticalAlign: "top"}} src='/images/Resource_power.gif'/>;
case 'modifiers\\cost_time_modifier.lua': case 'modifiers\\cost_time_modifier.lua':
return <AvTimerOutlinedIcon return <AvTimerOutlinedIcon
style={{verticalAlign: "top", fontSize: "18px"}}/>; style={{verticalAlign: "top", fontSize: "18px"}}/>;
@ -140,7 +149,8 @@ export function ModifiersProvidesAddonTable (props: IModifiersProvidesTable) {
sx={{'&:last-child td, &:last-child th': {border: 0}}} sx={{'&:last-child td, &:last-child th': {border: 0}}}
> >
<TableCell component="th" scope="row">{getModName(m.reference)}</TableCell> <TableCell 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>
)} )}
</Table> </Table>
@ -166,7 +176,8 @@ export function ModifiersProvidesTable (props: IModifiersProvidesResearchTable)
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 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/${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}
@ -184,7 +195,7 @@ export function ModifiersProvidesTable (props: IModifiersProvidesResearchTable)
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>{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}
</a> </span> </a> </span>
@ -192,11 +203,11 @@ export function ModifiersProvidesTable (props: IModifiersProvidesResearchTable)
} }
{ {
affectedWeapon.sergeants.map(affectedSergeant => affectedWeapon.sergeants.map(affectedSergeant =>
<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)}/><a 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}
</a> </span> </a> </span>
) )
@ -204,7 +215,7 @@ export function ModifiersProvidesTable (props: IModifiersProvidesResearchTable)
{ {
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//${props.modId}/race/${props.race.id}/building/${affectedBuilding.id}`}> href={`/mod/${props.modId}/race/${props.race.id}/building/${affectedBuilding.id}`}>
{affectedBuilding.name} {affectedBuilding.name}
</a> </span> </a> </span>
) )
@ -224,10 +235,18 @@ export function ModifiersProvidesTable (props: IModifiersProvidesResearchTable)
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)}</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"
<TableCell component="th" scope="row">{getModIcon(m.reference)} {getChangeDescription(m.usageType, m.value)} scope="row">{getModName(m.reference)}</TableCell>
{m.maxLifeTime !== undefined && m.maxLifeTime > 0 && <span><img style={{verticalAlign: "top"}} src='/images/Time_icon.webp'/>{m.maxLifeTime}s <TableCell component="th"
</span> }<i style={{fontSize: 11}}>{m.exclusive ? " does not stuck" : " does stuck"}</i></TableCell> scope="row">{getModIcon(m.reference)} {getChangeDescription(m.usageType, m.value)}
{m.maxLifeTime !== undefined && m.maxLifeTime > 0 &&
<span><img style={{verticalAlign: "top"}} src='/images/Time_icon.webp'/>{m.maxLifeTime}s
</span>}
<i style={{fontSize: 11}}>{m.exclusive ? " does not stuck" : " does stuck"}</i>
{m.probabilityOfApplying !== undefined && m.probabilityOfApplying !== 1.0 &&
<span><i style={{fontSize: 11}}> ({m.probabilityOfApplying * 100}% chance)</i>
</span>}
</TableCell>
</TableRow> </TableRow>
)} )}
</Table> </Table>

View File

@ -3,7 +3,8 @@ import {IBuildingShort} from "../types/IBuildingShort";
import {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 {IRequirement, IRequirementLimitByBuildingDto} from "../types/IRequirement"; import {IRequirement, IRequirementLimitByBuildingDto, IRequirementSquadsDto} from "../types/IRequirement";
import {IUnitShort} from "../types/IUnitShort";
interface IRequiredProps{ interface IRequiredProps{
requirement: IRequirement, requirement: IRequirement,
@ -25,7 +26,7 @@ function Required (props: IRequiredProps) {
)}</div> )}</div>
} }
function renderRequirementBuilding(requirementBuildings: IBuildingShort[],) { function renderRequirementBuildingEither(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('\\', '/')}/>
@ -38,6 +39,22 @@ function Required (props: IRequiredProps) {
); );
} }
function renderRequiremenStructureExclusive(buildingExclusive: IBuildingShort) {
return <div>&nbsp; Can't be build with: <img style={{verticalAlign: "top", height: 25}}
src={IconUrl + buildingExclusive.icon.replaceAll('\\', '/')}/>
&nbsp;{" "}<a href={`/mod/${props.modId}/race/${props.raceId}/building/${buildingExclusive.id}`}>
{buildingExclusive.name}
</a> </div>
}
function renderRequiremenAddonExclusive(addonShort: IBuildingAddonShort) {
return <div>&nbsp; Can't be build with: <img style={{verticalAlign: "top", height: 25}}
src={getIcon(addonShort.icon)}/>
&nbsp;<a href={`/mod/${props.modId}/race/${props.raceId}/building/${addonShort.buildingId}#addon-${addonShort.id}`}>
{addonShort.name}
</a></div>
}
function renderRequirementOwnership(requirementOwnership: string[],) { function renderRequirementOwnership(requirementOwnership: string[],) {
return requirementOwnership.length > 0 && <span>&nbsp; Owner: {requirementOwnership.map(o => { return requirementOwnership.length > 0 && <span>&nbsp; Owner: {requirementOwnership.map(o => {
switch(o) { switch(o) {
@ -68,6 +85,31 @@ function Required (props: IRequiredProps) {
)}</div> )}</div>
} }
function renderRequirementSquads(requirementSquads: IRequirementSquadsDto[],) {
return <div> {requirementSquads.map(rs =>
<span>&nbsp; Squad: {rs.count} <img style={{verticalAlign: "top", height: 25}}
src={getIcon(rs.squad.icon)}/>
&nbsp;<a href={`/mod/${props.modId}/race/${props.raceId}/unit/${rs.squad.id}`}>
{rs.squad.name}
</a></span>
)}</div>
}
function renderRequirementResearchesEither(requirementResearches: IResearchRequirements[],) {
console.log(requirementResearches);
return requirementResearches.length > 0 && (
<div>&nbsp; Researches: <span> <img style={{verticalAlign: "top", height: 25}}
src={getIcon(requirementResearches[0].researchShortDto.icon)}/>
&nbsp;<a href={`/mod/${props.modId}/race/${props.raceId}/building/${requirementResearches[0].researchShortDto.buildingId}#research-${requirementResearches[0].researchShortDto.id}`}>
{requirementResearches[0].researchShortDto.name}
</a></span> {requirementResearches[1] != null && <span> or <img style={{verticalAlign: "top", height: 25}} src={getIcon(requirementResearches[1].researchShortDto.icon)}/>
&nbsp; <a href={`/mod/${props.modId}/race/${props.raceId}/building/${requirementResearches[1].researchShortDto.buildingId}#research-${requirementResearches[1].researchShortDto.id}`}>
{requirementResearches[1].researchShortDto.name}
</a></span>} </div>
);
}
const requirement = props.requirement const requirement = props.requirement
@ -79,6 +121,11 @@ function Required (props: IRequiredProps) {
src="/images/Resource_orksquadcap.gif"/>&nbsp; src="/images/Resource_orksquadcap.gif"/>&nbsp;
{requirement.requiredTotalPop}</div> {requirement.requiredTotalPop}</div>
} }
{requirement.mobBonus !== null && requirement.mobBonus !== undefined &&
<div>&nbsp; Mob requirement: <img style={{verticalAlign: "top", height: 25}}
src="/images/Mob_bonus.gif"/>&nbsp;
{requirement.mobBonus.mobvalueRequired} in radius {requirement.mobBonus.proximityRequired}</div>
}
{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;
@ -88,6 +135,8 @@ function Required (props: IRequiredProps) {
{requirement.replaceWhenDone && <i> (old provides replace)</i>} {requirement.replaceWhenDone && <i> (old provides replace)</i>}
</div> </div>
} }
{requirement.requirementAddonExclusive != null &&
renderRequiremenAddonExclusive(requirement.requirementAddonExclusive,)}
{requirement.requirementBuildings.map(b => {requirement.requirementBuildings.map(b =>
<div key={b.id}>&nbsp; Building: <img style={{verticalAlign: "top", height: 25}} <div key={b.id}>&nbsp; Building: <img style={{verticalAlign: "top", height: 25}}
src={IconUrl + b.icon.replaceAll('\\', '/')}/>&nbsp; src={IconUrl + b.icon.replaceAll('\\', '/')}/>&nbsp;
@ -95,8 +144,14 @@ function Required (props: IRequiredProps) {
} }
{requirement.requirementResearches.length !== 0 && {requirement.requirementResearches.length !== 0 &&
renderRequirementResearches(requirement.requirementResearches,)} renderRequirementResearches(requirement.requirementResearches,)}
{requirement.requirementSquads.length !== 0 &&
renderRequirementSquads(requirement.requirementSquads,)}
{requirement.requirementResearchesEither.length !== 0 &&
renderRequirementResearchesEither(requirement.requirementResearchesEither,)}
{requirement.requirementBuildingsEither.length !== 0 && {requirement.requirementBuildingsEither.length !== 0 &&
renderRequirementBuilding(requirement.requirementBuildingsEither,)} renderRequirementBuildingEither(requirement.requirementBuildingsEither,)}
{requirement.requirementStructureExclusive != null &&
renderRequiremenStructureExclusive(requirement.requirementStructureExclusive,)}
{requirement.limitByBuilding !== undefined && requirement.limitByBuilding !== null && renderLimitPerBuilding(requirement.limitByBuilding)} {requirement.limitByBuilding !== undefined && requirement.limitByBuilding !== null && renderLimitPerBuilding(requirement.limitByBuilding)}
{requirement.requirementsGlobalAddons.length !== 0 && {requirement.requirementsGlobalAddons.length !== 0 &&
renderRequirementGlobalAddons(requirement.requirementsGlobalAddons,)} renderRequirementGlobalAddons(requirement.requirementsGlobalAddons,)}

View File

@ -11,6 +11,7 @@ import {Irace} from "../types/Irace";
import Required from "./Required"; import Required from "./Required";
import {ModifiersProvidesTable} from "./ModifiersProvideTable"; import {ModifiersProvidesTable} from "./ModifiersProvideTable";
import Ability from "./Ability"; import Ability from "./Ability";
import DeathExplosion from "./DeathExplosion";
export interface SergeantProps { export interface SergeantProps {
@ -120,6 +121,14 @@ const Sergeant = (props: SergeantProps) => {
src="/images/Kills_icon.webp"/> -{sergeant.moraleDeathPenalty} src="/images/Kills_icon.webp"/> -{sergeant.moraleDeathPenalty}
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow
sx={{'&:last-child td, &:last-child th': {border: 0}}}
>
<TableCell component="th" scope="row">Mass</TableCell>
<TableCell component="th" scope="row">
{sergeant.mass}
</TableCell>
</TableRow>
<TableRow <TableRow
sx={{'&:last-child td, &:last-child th': {border: 0}}} sx={{'&:last-child td, &:last-child th': {border: 0}}}
> >
@ -128,6 +137,14 @@ const Sergeant = (props: SergeantProps) => {
<Vision sight={sergeant.sightRadius} detect={sergeant.detectRadius}/> <Vision sight={sergeant.sightRadius} detect={sergeant.detectRadius}/>
</TableCell> </TableCell>
</TableRow> </TableRow>
{sergeant.mobValue != null &&
<TableRow>
<TableCell>Mob value</TableCell>
<TableCell>
<span> <img style={{height: 20, verticalAlign: "top"}} src="/images/Mob_bonus.gif"/> {sergeant.mobValue} </span>
</TableCell>
</TableRow>
}
</TableBody> </TableBody>
</Table> </Table>
</TableContainer> </TableContainer>
@ -157,6 +174,13 @@ const Sergeant = (props: SergeantProps) => {
return a - b; return a - b;
}).map(h => <WeaponSlot key ={h} 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>
{sergeant.deathExplosions.length > 0 &&
<Grid2 size={12}>
{sergeant.deathExplosions.map(da =>
<DeathExplosion deathExplosion={da} mod={props.mod}/>
)}
</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)}
</Grid2> </Grid2>

View File

@ -264,7 +264,7 @@ export default function WeaponFull(props: {weaponId: number, isDefault: Boolean,
<ToggleButton size="small" value="one hit">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.name.includes("Ultimate Apocalypse") ? { props.mod !== undefined && props.mod.technicalName === 'UltimateApocalypse' ?
<Table sx={{marginTop: "10px", textAlign: "center"}} size="small" aria-label="a dense table"> <Table sx={{marginTop: "10px", textAlign: "center"}} size="small" aria-label="a dense table">
<TableHead> <TableHead>
<TableRow> <TableRow>

View File

@ -30,6 +30,7 @@ import Research, {renderAffectedResearches} from "../classes/building/Research";
import Required from "../classes/Required"; 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";
interface UintPageState { interface UintPageState {
building: IBuilding, building: IBuilding,
@ -198,6 +199,13 @@ function Building(building: IBuilding, mod: IMod) {
<Ability mod={mod} ability={a} race={building.race}/> <Ability mod={mod} ability={a} race={building.race}/>
)} )}
</Grid2>} </Grid2>}
{building.deathExplosions.length > 0 &&
<Grid2 size={12}>
{building.deathExplosions.map(da =>
<DeathExplosion deathExplosion={da} mod={mod}/>
)}
</Grid2>
}
{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 =>

View File

@ -26,8 +26,7 @@ function Mods (mods: IMod[]) {
return( return(
<div> <div>
<h1>{modName}</h1> <h1>{modName}</h1>
{modName == "Unification new races" && <ul><a href="https://dawn-of-war-unification-mod.fandom.com/">Official unification wiki</a></ul>}
{modName == "Unification new races" && <ul><a href="https://dawn-of-war-unification-mod.fandom.com/"><img src="/images/mods/Uni_Lionhead.webp" width='50'/>Official unification wiki<img src="/images/mods/Uni_Lionhead.webp" width='50'/></a></ul>}
{sameMods.filter((m) => !m.isBeta).map(mod => {sameMods.filter((m) => !m.isBeta).map(mod =>
<ul><NavLink state={mod.id} to= {"/mod/" + mod.id} >{mod.version}</NavLink></ul>)} <ul><NavLink state={mod.id} to= {"/mod/" + mod.id} >{mod.version}</NavLink></ul>)}
{sameMods.find((m) => m.isBeta) != null && <div><i>Beta versions:</i></div>} {sameMods.find((m) => m.isBeta) != null && <div><i>Beta versions:</i></div>}

View File

@ -29,6 +29,7 @@ import Required from "../classes/Required";
import {renderAffectedResearches} from "../classes/building/Research"; 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";
interface UintPageState { interface UintPageState {
unit: IUnit, unit: IUnit,
@ -254,6 +255,14 @@ function Unit(unit: IUnit, mod: IMod) {
</TableCell> </TableCell>
</TableRow> </TableRow>
} }
{unit.mobValue != null &&
<TableRow>
<TableCell>Mob value</TableCell>
<TableCell>
<span> <img style={{height: 20, verticalAlign: "top"}} src="/images/Mob_bonus.gif"/> {unit.mobValue} </span>
</TableCell>
</TableRow>
}
{unit.squadLimit !== undefined && unit.squadLimit !== null && {unit.squadLimit !== undefined && unit.squadLimit !== null &&
<TableRow> <TableRow>
<TableCell>Limit</TableCell> <TableCell>Limit</TableCell>
@ -292,6 +301,15 @@ function Unit(unit: IUnit, mod: IMod) {
</Accordion>)} </Accordion>)}
</Grid2> </Grid2>
{unit.moraleMax !== null && !(unit.moraleBrakeModifiers.find(m => m.reference.includes("accuracy_weapon_modifier") && m.value === 0.2) !== undefined &&
unit.moraleBrakeModifiers.find(m => m.reference.includes("speed_maximum_modifier") && m.value === 1.2) !== undefined &&
unit.moraleBrakeModifiers.length === 2)
&& <Grid2 size={12}>
<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}/>
</Grid2>}
{unit.modifiers.length > 0 && <Grid2 size={12}> {unit.modifiers.length > 0 && <Grid2 size={12}>
<h3>Affected on</h3> <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}/>
@ -309,6 +327,13 @@ function Unit(unit: IUnit, mod: IMod) {
return a - b; return a - b;
}).map(h => <WeaponSlot haveReinforceMenu={unit.haveReinforceMenu} key ={h} 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>
{unit.deathExplosions.length > 0 &&
<Grid2 size={12}>
{unit.deathExplosions.map(da =>
<DeathExplosion deathExplosion={da} mod={mod}/>
)}
</Grid2>
}
<Grid2 size={12}> <Grid2 size={12}>
{renderAffectedResearches(unit.affectedResearches, mod.id, unit.race.id)} {renderAffectedResearches(unit.affectedResearches, mod.id, unit.race.id)}
</Grid2> </Grid2>

View File

@ -2,6 +2,8 @@ import {IModifier} from "./IModifier";
import {IRequirement} from "./IRequirement"; import {IRequirement} from "./IRequirement";
import {IArmorType} from "./IArmorType"; import {IArmorType} from "./IArmorType";
import {IAffectedData} from "./IAffectedData"; import {IAffectedData} from "./IAffectedData";
import {IPiercing} from "./IPiercing";
import {IAbilityEnvironment} from "./IAbilityEnvironment";
export interface IAbilityShort { export interface IAbilityShort {
id: number; id: number;
@ -32,7 +34,6 @@ export interface IAbilityFill {
rechargeTimerGlobal?: boolean; rechargeTimerGlobal?: boolean;
refreshTime?: number; refreshTime?: number;
durationTime?: number; durationTime?: number;
spawnedEntityName?: string;
radius?: number; radius?: number;
minDamage?: number; minDamage?: number;
minDamageValue?: number; minDamageValue?: number;
@ -47,10 +48,6 @@ export interface IAbilityFill {
requirements?: IRequirement; requirements?: IRequirement;
affectedData: IAffectedData, affectedData: IAffectedData,
targetFilter: IArmorType[]; targetFilter: IArmorType[];
piercings: IAbilityPiercing[]; piercings: IPiercing[];
} abilityEnvironment: IAbilityEnvironment;
export interface IAbilityPiercing {
armorType: IArmorType
piercingValue: number
} }

View File

@ -0,0 +1,26 @@
import {IModifier} from "./IModifier";
import {IRequirement} from "./IRequirement";
import {IArmorType} from "./IArmorType";
import {IAffectedData} from "./IAffectedData";
import {IAbilityShort} from "./IAbility";
import {IDeathExplosion} from "./IDeathExplosion";
export interface IAbilityEnvironment {
id: number;
modId: number;
filename: string;
name?: string | null;
description?: string | null;
icon?: string | null;
health?: number | null;
armour?: number | null;
healthRegeneration?: number | null;
moveSpeed?: number | null;
sightRadius?: number | null;
detectRadius?: number | null;
lifetime?: number | null;
armorType: IArmorType | null;
armorType2: IArmorType | null;
abilities: IAbilityShort[];
deathExplosions: IDeathExplosion[];
}

View File

@ -7,6 +7,7 @@ import {IRequirement} from "./IRequirement";
import {IResearchShort} from "./IResearchShort"; import {IResearchShort} from "./IResearchShort";
import {IAffectedData} from "./IAffectedData"; import {IAffectedData} from "./IAffectedData";
import {IAbilityShort} from "./IAbility"; import {IAbilityShort} from "./IAbility";
import {IDeathExplosion} from "./IDeathExplosion";
export interface IBuilding { export interface IBuilding {
id: number id: number
@ -42,6 +43,7 @@ export interface IBuilding {
units: IUnitShort[] units: IUnitShort[]
affectedResearches: IResearchShort[], affectedResearches: IResearchShort[],
requirements: IRequirement, requirements: IRequirement,
deathExplosions: IDeathExplosion[],
hotkey: string hotkey: string
} }

View File

@ -0,0 +1,22 @@
import {IModifier} from "./IModifier";
import {IRequirement} from "./IRequirement";
import {IArmorType} from "./IArmorType";
import {IAffectedData} from "./IAffectedData";
import {IAbilityShort} from "./IAbility";
import {IPiercing} from "./IPiercing";
export interface IDeathExplosion {
id?: number | null;
globalChance: number;
chance: number;
minDamage?: number ;
maxDamage?: number ;
minDamageValue?: number;
moraleDamage?: number;
damageRadius?: number | null;
throwForceMin?: number | null;
throwForceMax?: number | null;
modId?: number | null;
modifiers: IModifier[];
armorPiercing: IPiercing[];
}

7
src/types/IPiercing.tsx Normal file
View File

@ -0,0 +1,7 @@
import {IArmorType} from "./IArmorType";
export interface IPiercing {
armorType: IArmorType
piercingValue: number
}

View File

@ -1,21 +1,37 @@
import {IBuildingShort} from "./IBuildingShort"; import {IBuildingShort} from "./IBuildingShort";
import {IBuildingAddonShort} from "./IBuilding"; import {IBuildingAddonShort} from "./IBuilding";
import {IResearchRequirements} from "./IResearchRequirements"; import {IResearchRequirements} from "./IResearchRequirements";
import {IUnitShort} from "./IUnitShort";
export interface IRequirement { export interface IRequirement {
requirementBuildings: IBuildingShort[]; requirementBuildings: IBuildingShort[];
requirementBuildingsEither: IBuildingShort[]; requirementBuildingsEither: IBuildingShort[];
requirementsGlobalAddons: IBuildingAddonShort[]; requirementsGlobalAddons: IBuildingAddonShort[];
requirementResearches: IResearchRequirements[]; requirementResearches: IResearchRequirements[];
requirementSquads: IRequirementSquadsDto[];
requirementResearchesEither: IResearchRequirements[];
replaceWhenDone: Boolean; replaceWhenDone: Boolean;
requireAddon: IBuildingAddonShort; requireAddon: IBuildingAddonShort;
requiredTotalPop?: number; requiredTotalPop?: number;
limitSquad?:number; limitSquad?:number;
limitTech?:number; limitTech?:number;
limitByBuilding ?: IRequirementLimitByBuildingDto; limitByBuilding ?: IRequirementLimitByBuildingDto;
mobBonus?: IRequirementMobBonusDto;
requirementStructureExclusive?: IBuildingShort;
requirementAddonExclusive?: IBuildingAddonShort;
requiredOwnership: string[]; requiredOwnership: string[];
} }
export interface IRequirementSquadsDto{
squad: IUnitShort;
count: number;
}
export interface IRequirementMobBonusDto{
mobvalueRequired: number;
proximityRequired: number;
}
export interface IRequirementLimitByBuildingDto{ export interface IRequirementLimitByBuildingDto{
building: IBuildingShort; building: IBuildingShort;
limit: number; limit: number;

View File

@ -5,6 +5,8 @@ import {IRequirement} from "./IRequirement";
import {IModifier} from "./IModifier"; import {IModifier} from "./IModifier";
import {IAffectedData} from "./IAffectedData"; import {IAffectedData} from "./IAffectedData";
import {IAbilityShort} from "./IAbility"; import {IAbilityShort} from "./IAbility";
import {IPiercing} from "./IPiercing";
import {IDeathExplosion} from "./IDeathExplosion";
export interface IUnitResponse { export interface IUnitResponse {
race: string race: string
@ -54,6 +56,7 @@ export interface IUnit {
faithIncome?: number faithIncome?: number
powerIncome?: number powerIncome?: number
requisitionIncome?: number requisitionIncome?: number
mobValue?: number
icon: string icon: string
modId: number modId: number
requirements: IRequirement requirements: IRequirement
@ -61,9 +64,11 @@ export interface IUnit {
sergeants: ISergeant[] sergeants: ISergeant[]
weapons: WeaponHardpoint[] weapons: WeaponHardpoint[]
modifiers: IModifier[] modifiers: IModifier[]
moraleBrakeModifiers: IModifier[]
abilities: IAbilityShort[] abilities: IAbilityShort[]
affectedData: IAffectedData, affectedData: IAffectedData,
affectedResearches: IResearchShort[], affectedResearches: IResearchShort[],
deathExplosions: IDeathExplosion[],
hotkey?: string, hotkey?: string,
} }
@ -83,6 +88,7 @@ export interface ISergeant {
faithIncome?: number faithIncome?: number
powerIncome?: number powerIncome?: number
requisitionIncome?: number requisitionIncome?: number
mobValue?: number
health: number health: number
armour?: number armour?: number
healthRegeneration: number healthRegeneration: number
@ -100,6 +106,7 @@ export interface ISergeant {
weapons: WeaponHardpoint[] weapons: WeaponHardpoint[]
abilities: IAbilityShort[] abilities: IAbilityShort[]
affectedResearches: IResearchShort[], affectedResearches: IResearchShort[],
deathExplosions: IDeathExplosion[],
hotkey?: string, hotkey?: string,
} }
@ -147,13 +154,8 @@ export interface IWeapon {
modId: number modId: number
requirements: IRequirement requirements: IRequirement
modifiers: IModifier[] modifiers: IModifier[]
weaponArmorPiercing: IWeaponPiercing[] weaponArmorPiercing: IPiercing[]
affectedResearches: IResearchShort[], affectedResearches: IResearchShort[],
hotkey?: string, hotkey?: string,
} }
export interface IWeaponPiercing {
armorType: IArmorType
piercingValue: number
}