Add research support
This commit is contained in:
parent
f94553bb9a
commit
851bb71601
1
.idea/inspectionProfiles/Project_Default.xml
generated
1
.idea/inspectionProfiles/Project_Default.xml
generated
@ -2,5 +2,6 @@
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="UsePropertyAccessSyntax" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
</profile>
|
||||
</component>
|
||||
@ -1,15 +1,16 @@
|
||||
import React from "react";
|
||||
import {Tooltip} from "@mui/material";
|
||||
import ArmorTypeValues from "../types/ArmorTypeValues";
|
||||
|
||||
interface IArmorType{
|
||||
name: string,
|
||||
withName: boolean
|
||||
compact: boolean
|
||||
}
|
||||
|
||||
class ArmorType extends React.Component<IArmorType, any> {
|
||||
|
||||
public static defaultProps = {
|
||||
withName: false
|
||||
compact: true
|
||||
};
|
||||
|
||||
renderArmorImage(armorTypeId: string): string {
|
||||
@ -20,11 +21,11 @@ class ArmorType extends React.Component<IArmorType, any> {
|
||||
return '/images/ARM_Inf_Mid.webp';
|
||||
case 'Infantry High':
|
||||
return '/images/ARM_Inf_Hi.webp';
|
||||
case 'Infantry Heavy Medium':
|
||||
case ArmorTypeValues.InfantryHeavyMedium:
|
||||
return '/images/ARM_Hvy_Inf_Mid.webp';
|
||||
case 'Infantry Heavy High':
|
||||
case ArmorTypeValues.InfantryHeavyHigh:
|
||||
return '/images/ARM_Hvy_Inf_Hi.webp';
|
||||
case 'Commander':
|
||||
case ArmorTypeValues.Commander:
|
||||
return '/images/ARM_Cmdr.webp';
|
||||
case 'Living Metal':
|
||||
return '/images/ARM_living_metal.webp';
|
||||
@ -34,7 +35,7 @@ class ArmorType extends React.Component<IArmorType, any> {
|
||||
return '/images/ARM_Veh_Mid.webp';
|
||||
case 'Vehicle High':
|
||||
return '/images/ARM_Veh_Hi.webp';
|
||||
case 'Air':
|
||||
case 'Vehicle Air':
|
||||
return '/images/ARM_Air.webp';
|
||||
case 'Building Low':
|
||||
return '/images/ARM_Bld_Lo.webp';
|
||||
@ -58,9 +59,14 @@ class ArmorType extends React.Component<IArmorType, any> {
|
||||
}
|
||||
|
||||
render() {
|
||||
if(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> :
|
||||
<span><img src={this.renderArmorImage(this.props.name)}/> {this.props.name}</span>} </span>);
|
||||
} else
|
||||
return <span ><img style={{verticalAlign: "top"}} src={this.renderArmorImage(this.props.name)}/> {this.props.name} </span>;
|
||||
|
||||
return (<Tooltip title={this.props.name}><span> <img style={{verticalAlign: "top"}}
|
||||
src={this.renderArmorImage(this.props.name)}/> {this.props.withName && this.props.name}</span></Tooltip>);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
export default class LobbyList extends React.Component {
|
||||
constructor(props){
|
||||
super(props);
|
||||
this.state = { messages : [] }
|
||||
}
|
||||
componentDidMount(){
|
||||
// this is an "echo" websocket service
|
||||
this.connection = new WebSocket('wss://echo.websocket.org');
|
||||
// listen to onmessage event
|
||||
this.connection.onmessage = evt => {
|
||||
// add the new message to state
|
||||
this.setState({
|
||||
messages : this.state.messages.concat([ evt.data ])
|
||||
})
|
||||
};
|
||||
// for testing purposes: sending to the echo service which will send it back back
|
||||
setInterval( _ => {
|
||||
this.connection.send( Math.random() )
|
||||
}, 2000 )
|
||||
}
|
||||
render() {
|
||||
// slice(-5) gives us the five most recent messages
|
||||
return <ul>{ this.state.messages.slice(-5).map( (msg, idx) => <li key={'msg-' + idx }>{ msg }</li> )}</ul>;
|
||||
}
|
||||
};
|
||||
223
src/classes/ModifiersProvideTable.tsx
Normal file
223
src/classes/ModifiersProvideTable.tsx
Normal file
@ -0,0 +1,223 @@
|
||||
import {Paper, Table, TableCell, TableContainer, TableRow} from "@mui/material";
|
||||
import React from "react";
|
||||
import {IModifier} from "../types/IModifier";
|
||||
import {IconUrl} from "../core/api";
|
||||
import {IResearch} from "../types/IResearch";
|
||||
import {Irace} from "../types/Irace";
|
||||
|
||||
interface IModifiersProvidesTable{
|
||||
modifiers: IModifier[],
|
||||
}
|
||||
|
||||
interface IModifiersProvidesResearchTable{
|
||||
modifiers: IModifier[],
|
||||
research: IResearch,
|
||||
race: Irace,
|
||||
}
|
||||
|
||||
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\\sight_radius_modifier.lua':
|
||||
return 'Sight';
|
||||
case 'modifiers\\garrison_requisition_modifier.lua':
|
||||
return 'Requisition';
|
||||
case 'modifiers\\faith_max_modifier.lua':
|
||||
return 'Faith max';
|
||||
case 'modifiers\\holy_icon_cost_power.lua':
|
||||
return <span>Next icon cost <img style={{verticalAlign: "top"}} src='/images/Resource_power.gif'/></span>;
|
||||
case 'modifiers\\holy_icon_cost_requisition.lua':
|
||||
return <span>Next icon cost <img style={{verticalAlign: "top"}} src='/images/Resource_requisition.gif'/></span>;
|
||||
case 'modifiers\\enable_hardpoint_02.lua':
|
||||
return 'Weapon slot 2';
|
||||
case 'modifiers\\default_weapon_modifier_hardpoint1.lua':
|
||||
return 'Weapon slot 1 change weapon';
|
||||
case 'modifiers\\default_weapon_modifier_hardpoint2.lua':
|
||||
return 'Weapon slot 2 change weapon';
|
||||
case 'modifiers\\default_weapon_modifier_hardpoint3.lua':
|
||||
return 'Weapon slot 3 change weapon';
|
||||
case 'modifiers\\default_weapon_modifier_hardpoint4.lua':
|
||||
return 'Weapon slot 4 change weapon';
|
||||
case 'modifiers\\default_weapon_modifier_hardpoint5.lua':
|
||||
return 'Weapon slot 5 change weapon';
|
||||
case 'modifiers\\default_weapon_modifier_hardpoint6.lua':
|
||||
return 'Weapon slot 6 change weapon';
|
||||
case 'modifiers\\morale_maximum_squad_modifier.lua':
|
||||
return 'Morale';
|
||||
case 'modifiers\\max_upgrades_squad_modifier.lua':
|
||||
return 'Max equip weapons';
|
||||
case 'modifiers\\speed_maximum_modifier.lua':
|
||||
return 'Max speed';
|
||||
case 'modifiers\\min_damage_weapon_modifier.lua':
|
||||
return 'Min damage';
|
||||
case 'modifiers\\max_damage_weapon_modifier.lua':
|
||||
return 'Max damage';
|
||||
case 'modifiers\\enable_armour_2.lua':
|
||||
return 'Change armor type';
|
||||
case 'modifiers\\cost_requisition_modifier.lua':
|
||||
return 'Requisition cost';
|
||||
default:
|
||||
return mt.replace("modifiers\\", "").replace("modifier.lua", "").replace(".lua", "").replaceAll("_", " ");
|
||||
}
|
||||
}
|
||||
|
||||
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\\sight_radius_modifier.lua':
|
||||
return <img style={{verticalAlign: "top"}} src='/images/DETECT_NO.webp'/>;
|
||||
case 'modifiers\\faith_max_modifier.lua':
|
||||
return <img style={{verticalAlign: "top"}} src='/images/Resource_faith.gif'/>;
|
||||
case 'modifiers\\garrison_requisition_modifier.lua':
|
||||
return <img style={{verticalAlign: "top"}} src='/images/Resource_requisition.gif'/>;
|
||||
case 'modifiers\\cost_requisition_modifier.lua':
|
||||
return <img style={{verticalAlign: "top"}} src='/images/Resource_requisition.gif'/>;
|
||||
case 'modifiers\\morale_maximum_squad_modifier.lua':
|
||||
return <img style={{verticalAlign: "top"}} src='/images/ARM_Morale.webp'/>;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
function getChangeDescription(ref: String, v: number) {
|
||||
switch(ref) {
|
||||
case 'type_modifierusagetype\\tp_mod_usage_addition.lua':
|
||||
if(v < 0){
|
||||
return v
|
||||
}else return '+' + v;
|
||||
case 'type_modifierusagetype\\tp_mod_usage_multiplication.lua':
|
||||
return 'x' + v;
|
||||
case 'type_modifierusagetype\\tp_mod_usage_percentage.lua':
|
||||
return '%' + v;
|
||||
case 'type_modifierusagetype\\tp_mod_usage_enable.lua':
|
||||
if(v === 1){
|
||||
return ' enable ';
|
||||
} else {
|
||||
return ' disable ';
|
||||
}
|
||||
default:
|
||||
return ref;
|
||||
}
|
||||
}
|
||||
|
||||
export function ModifiersProvidesAddonTable (props: IModifiersProvidesTable) {
|
||||
|
||||
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>
|
||||
)
|
||||
}
|
||||
|
||||
export function ModifiersProvidesResearchTable (props: IModifiersProvidesResearchTable) {
|
||||
|
||||
let mods = props.modifiers
|
||||
|
||||
function getTarget(target: String, research: IResearch, race: Irace) {
|
||||
console.log(research.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);
|
||||
if(affectedUnit != null) {
|
||||
return <span><img style={{verticalAlign: "top", height: 25}}
|
||||
src={getIcon(affectedUnit.icon)}/><a
|
||||
href={`/mod/${research.modId}/race/${race.id}/unit/${affectedUnit.id}`}>
|
||||
{affectedUnit.name}
|
||||
</a></span>
|
||||
}
|
||||
var affectedSergeant = research.affectedSergeants.find(as => as.filename.replaceAll('.rgd', '') === target);
|
||||
if(affectedSergeant != null) {
|
||||
return <span><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
|
||||
href={`/mod/${research.modId}/race/${race.id}/unit/${affectedSergeant.unit.id}`}>
|
||||
{affectedSergeant.unit.name}
|
||||
</a></span>
|
||||
}
|
||||
var affectedBuilding = research.affectedBuildings.find(ab => ab.filename.replaceAll('.rgd', '') === target);
|
||||
if(affectedBuilding != null) {
|
||||
return <span><img style={{verticalAlign: "top", height: 25}} src={getIcon(affectedBuilding.icon)}/><a
|
||||
href={`/mod/${research.modId}/race/${race.id}/building/${affectedBuilding.id}`}>
|
||||
{affectedBuilding.name}
|
||||
</a> </span>
|
||||
}
|
||||
|
||||
var affectedWeapon = research.affectedWeapons.find(aw => aw.filename.replaceAll('.rgd', '') === target);
|
||||
if (affectedWeapon != null) {
|
||||
return <span>{affectedWeapon.name ? affectedWeapon.name : affectedWeapon.filename.replaceAll('_', ' ').replace('.rgd', '')} at {
|
||||
affectedWeapon.units.map(unit =>
|
||||
<span><img style={{verticalAlign: "top", height: 25}} src={getIcon(unit.icon)}/><a
|
||||
href={`/mod/${research.modId}/race/${race.id}/unit/${unit.id}`}>
|
||||
{unit.name}
|
||||
</a> </span>
|
||||
)
|
||||
}
|
||||
{
|
||||
affectedWeapon.sergeants.map(affectedSergeant =>
|
||||
<span><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
|
||||
href={`/mod/${research.modId}/race/${race.id}/unit/${affectedSergeant.unit.id}`}>
|
||||
{affectedSergeant.unit.name}
|
||||
</a> </span>
|
||||
)
|
||||
}
|
||||
{
|
||||
affectedWeapon.buildings.map(affectedBuilding =>
|
||||
<span><img style={{verticalAlign: "top", height: 25}} src={getIcon(affectedBuilding.icon)}/><a
|
||||
href={`/mod/${research.modId}/race/${race.id}/building/${affectedBuilding.id}`}>
|
||||
{affectedBuilding.name}
|
||||
</a> </span>
|
||||
)
|
||||
}
|
||||
</span>
|
||||
}
|
||||
|
||||
|
||||
return <span>Unknown target <i>{target}</i></span>;
|
||||
}
|
||||
|
||||
return (
|
||||
<TableContainer component={Paper}>
|
||||
<Table size="small" aria-label="a dense table">
|
||||
{mods.map(m =>
|
||||
<TableRow
|
||||
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||
>
|
||||
<TableCell component="th" scope="row">{getTarget(m.target, props.research, props.race)}</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>
|
||||
</TableRow>
|
||||
)}
|
||||
</Table>
|
||||
</TableContainer>
|
||||
)
|
||||
}
|
||||
|
||||
export function getIcon(icon?: string): string{
|
||||
if(icon !== null && icon !== undefined){
|
||||
return IconUrl + icon.replaceAll('\\', '/')
|
||||
} else return '/images/shakal.png'
|
||||
}
|
||||
|
||||
|
||||
97
src/classes/Required.tsx
Normal file
97
src/classes/Required.tsx
Normal file
@ -0,0 +1,97 @@
|
||||
import {Paper, Table, TableCell, TableContainer, TableRow} from "@mui/material";
|
||||
import React from "react";
|
||||
import {IModifier} from "../types/IModifier";
|
||||
import {IBuildingShort} from "../types/IBuildingShort";
|
||||
import {IBuilding, IBuildingAddonShort} from "../types/IBuilding";
|
||||
import {IconUrl} from "../core/api";
|
||||
import {IResearchRequirements} from "../types/IResearchRequirements";
|
||||
import {goToAddon} from "../pages/BuildingPage";
|
||||
import {IRequirement} from "../types/IRequirement";
|
||||
|
||||
interface IRequiredProps{
|
||||
requirement: IRequirement,
|
||||
building: IBuilding,
|
||||
}
|
||||
|
||||
function Required (props: IRequiredProps) {
|
||||
|
||||
function renderRequirementGlobalAddons(rgas: IBuildingAddonShort[], building: IBuilding, modId: number) {
|
||||
|
||||
return <div> {rgas.map(rga =>
|
||||
|
||||
<span> Global addon: <img style={{verticalAlign: "top", height: 25}}
|
||||
src={getIcon(rga.icon)}/>
|
||||
<a href={`/mod/${modId}/race/${building.race.id}/building/${rga.buildingId}#addon-${rga.id}`}>
|
||||
{rga.name}
|
||||
</a></span>
|
||||
)}</div>
|
||||
}
|
||||
|
||||
function renderRequirementBuilding(requirementBuildings: IBuildingShort[], building: IBuilding, modId: number) {
|
||||
return requirementBuildings.length > 0 && (
|
||||
<div> Buildings: <img style={{verticalAlign: "top", height: 25}}
|
||||
src={IconUrl + requirementBuildings[0].icon.replaceAll('\\', '/')}/>
|
||||
{" "}<a href={`/mod/${modId}/race/${building.race.id}/building/${requirementBuildings[0].id}`}>
|
||||
{requirementBuildings[0].name}
|
||||
</a> {requirementBuildings[1] !== undefined && <span>or <img style={{verticalAlign: "top", height: 25}}
|
||||
src={IconUrl + requirementBuildings[1].icon.replaceAll('\\', '/')}/>
|
||||
{" "}<a href={`/mod/${modId}/race/${building.race.id}/building/${requirementBuildings[1].id}`}>
|
||||
{requirementBuildings[1].name}</a></span> } </div>
|
||||
);
|
||||
}
|
||||
|
||||
function renderRequirementResearches(requirementResearches: IResearchRequirements[], modId: number, raceId: string) {
|
||||
return <div> {requirementResearches.map(rs =>
|
||||
|
||||
<span> Research {rs.researchMustNotBeComplete ? "not" : ""}: <img style={{verticalAlign: "top", height: 25}}
|
||||
src={getIcon(rs.researchShortDto.icon)}/>
|
||||
<a href={`/mod/${modId}/race/${raceId}/building/${rs.researchShortDto.buildingId}#research-${rs.researchShortDto.id}`}>
|
||||
{rs.researchShortDto.name}
|
||||
</a></span>
|
||||
)}</div>
|
||||
}
|
||||
|
||||
const requirement = props.requirement
|
||||
const building = props.building
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h4>Required: </h4>
|
||||
{requirement.requiredTotalPop !== undefined && requirement.requiredTotalPop !== null &&
|
||||
<div> Population: <img style={{verticalAlign: "top", height: 25}}
|
||||
src="/images/Resource_orksquadcap.gif"/>
|
||||
{requirement.requiredTotalPop}</div>
|
||||
}
|
||||
{requirement.requireAddon !== null &&
|
||||
<div> Addon: <img style={{verticalAlign: "top", height: 25}}
|
||||
src={IconUrl + requirement.requireAddon.icon.replaceAll('\\', '/')}/>
|
||||
<a href={"#addon-" + requirement.requireAddon.id} onClick={() => goToAddon(`#addon-` + requirement.requireAddon.id)}>{requirement.requireAddon.name}</a>
|
||||
{requirement.replaceWhenDone && <i> (old provides replace)</i>}
|
||||
</div>
|
||||
}
|
||||
{requirement.requirementBuildings.map(b =>
|
||||
<div> Building: <img style={{verticalAlign: "top", height: 25}}
|
||||
src={IconUrl + b.icon.replaceAll('\\', '/')}/>
|
||||
<a href= {'/mod/'+ building.modId +'/race/'+ building.race.id +'/building/' + b.id + "/"}>{b.name}</a></div>)
|
||||
}
|
||||
{requirement.requirementResearches.length !== 0 &&
|
||||
renderRequirementResearches(requirement.requirementResearches, building.modId, building.race.id)}
|
||||
{requirement.requirementBuildingsEither.length !== 0 &&
|
||||
renderRequirementBuilding(requirement.requirementBuildingsEither, building, building.modId)}
|
||||
{requirement.requirementsGlobalAddons.length !== 0 &&
|
||||
renderRequirementGlobalAddons(requirement.requirementsGlobalAddons, building, building.modId)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function getIcon(icon?: string): string{
|
||||
if(icon !== null && icon !== undefined){
|
||||
return IconUrl + icon.replaceAll('\\', '/')
|
||||
} else return '/images/shakal.png'
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
export default Required;
|
||||
@ -18,12 +18,15 @@ import {ExpandMore} from "@mui/icons-material";
|
||||
import WeaponSlot from "./WeaponSlot";
|
||||
import Vision from "./Vision";
|
||||
import {IMod} from "../types/Imod";
|
||||
import {renderAffectedResearches} from "./building/Research";
|
||||
import {Irace} from "../types/Irace";
|
||||
|
||||
|
||||
|
||||
export interface SergeantProps {
|
||||
sergeant: ISergeant,
|
||||
mod: IMod
|
||||
mod: IMod,
|
||||
race: Irace,
|
||||
}
|
||||
|
||||
const Sergeant = (props: SergeantProps) => {
|
||||
@ -100,7 +103,9 @@ const Sergeant = (props: SergeantProps) => {
|
||||
>
|
||||
<TableCell component="th" scope="row">Armor type</TableCell>
|
||||
<TableCell component="th" scope="row">
|
||||
<ArmorType name={sergeant.armorType.name}/>
|
||||
<ArmorType name={sergeant.armorType.name} compact={false}/>
|
||||
{sergeant.armorType2 && <span style={{fontSize: 12}} ><br/><i>after upgrade can become:<br/><ArmorType
|
||||
name={sergeant.armorType2.name} compact={false}/></i></span> }
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow
|
||||
@ -126,7 +131,7 @@ const Sergeant = (props: SergeantProps) => {
|
||||
<TableRow
|
||||
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">
|
||||
<Vision sight={sergeant.sightRadius} detect={sergeant.detectRadius}/>
|
||||
</TableCell>
|
||||
@ -144,7 +149,10 @@ const Sergeant = (props: SergeantProps) => {
|
||||
<Grid2 size={12}>
|
||||
{[...mapWithUnitWeapons.keys()].sort(function (a, b) {
|
||||
return a - b;
|
||||
}).map(h => <WeaponSlot mod={props.mod} unitWeapons={mapWithUnitWeapons.get(h)} hardpoint={h}/>)}
|
||||
}).map(h => <WeaponSlot race={props.race} mod={props.mod} unitWeapons={mapWithUnitWeapons.get(h)} hardpoint={h}/>)}
|
||||
</Grid2>
|
||||
<Grid2 size={12}>
|
||||
{renderAffectedResearches(sergeant.affectedResearches, props.mod.id, props.race.id)}
|
||||
</Grid2>
|
||||
</Grid2>
|
||||
<i className="rgdFrom">{sergeant.filename}</i>
|
||||
|
||||
@ -1,54 +0,0 @@
|
||||
import React from 'react';
|
||||
import Item from "./Item";
|
||||
|
||||
export class TimerExample extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
// Don't call this.setState() here!
|
||||
this.state = { elapsed: 10 };
|
||||
this.tick = this.tick.bind(this);
|
||||
console.log(this.props);
|
||||
}
|
||||
|
||||
|
||||
componentDidMount() {
|
||||
|
||||
// componentDidMount вызывается react'ом, когда компонент
|
||||
// был отрисован на странице. Мы можем установить интервал здесь:
|
||||
console.log(this.props);
|
||||
|
||||
this.timer = setInterval(this.tick, 50);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
||||
// Этот метод вызывается сразу после того, как компонент удален
|
||||
// со страницы и уничтожен. Мы можем удалить интервал здесь:
|
||||
|
||||
clearInterval(this.timer);
|
||||
}
|
||||
|
||||
tick() {
|
||||
|
||||
// Эта функция вызывается каждые 50мс. Она обновляет
|
||||
// счетчик затраченного времени. Вызов setState заставляет компонент перерисовываться
|
||||
console.log(this.state);
|
||||
|
||||
this.setState({elapsed: new Date() - this.props.start});
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
|
||||
let elapsed = Math.round(this.state.elapsed / 100);
|
||||
|
||||
// Это даст нам число с одной цифрой после запятой dot (xx.x):
|
||||
let seconds = (elapsed / 10).toFixed(1);
|
||||
|
||||
// Хоть мы и возвращаем целый <p> элемент, react разумно обновит
|
||||
// только измененные части, содержащие переменную seconds.
|
||||
|
||||
return <p>This example was started <b>{seconds} seconds</b> ago.</p>;
|
||||
}
|
||||
};
|
||||
@ -21,11 +21,14 @@ import {IconUrl} from "../core/api";
|
||||
import {ExpandMore} from "@mui/icons-material";
|
||||
import Sergeant from "./Sergeant";
|
||||
import {IMod} from "../types/Imod";
|
||||
import {Irace} from "../types/Irace";
|
||||
import {renderAffectedResearches} from "./building/Research";
|
||||
|
||||
interface IWeaponProps {
|
||||
weapon: IWeapon,
|
||||
isDefault: Boolean,
|
||||
mod: IMod,
|
||||
race: Irace,
|
||||
}
|
||||
|
||||
interface IWeaponState {
|
||||
@ -74,7 +77,7 @@ class Weapon extends React.Component<IWeaponProps, any> {
|
||||
const infMedPiercing = this.getPiercingK(ArmorTypeNames.InfantryMedium)
|
||||
const infHighPiercing = this.getPiercingK(ArmorTypeNames.InfantryHigh)
|
||||
const infHeavyMedPiercing = this.getPiercingK(ArmorTypeNames.InfantryHeavyMedium)
|
||||
const infHeavyHighPiercing = this.getPiercingK(ArmorTypeNames.InfantryHeavyMedium)
|
||||
const infHeavyHighPiercing = this.getPiercingK(ArmorTypeNames.InfantryHeavyHigh)
|
||||
const demonPiercing = this.getPiercingK(ArmorTypeNames.DemonMedium)
|
||||
const demonHighPiercing = this.getPiercingK(ArmorTypeNames.DemonHigh)
|
||||
const commanderPiercing = this.getPiercingK(ArmorTypeNames.Commander)
|
||||
@ -120,13 +123,16 @@ class Weapon extends React.Component<IWeaponProps, any> {
|
||||
|
||||
const StyledTableCell = styled(TableCell)(({theme}) => ({
|
||||
[`&.${tableCellClasses.head}`]: {
|
||||
backgroundColor: "rgb(234, 234, 234)",
|
||||
color: theme.palette.common.white,
|
||||
backgroundColor: "rgb(244,244,244)",
|
||||
marginRight: 'auto',
|
||||
marginLeft: 'auto',
|
||||
paddingLeft: 10
|
||||
},
|
||||
[`&.${tableCellClasses.body}`]: {
|
||||
fontSize: 13,
|
||||
paddingLeft: 10,
|
||||
fontSize: 12,
|
||||
textAlign: 'center',
|
||||
paddingRight: 18,
|
||||
paddingLeft: 10
|
||||
},
|
||||
}));
|
||||
|
||||
@ -276,7 +282,7 @@ class Weapon extends React.Component<IWeaponProps, any> {
|
||||
</ToggleButtonGroup>
|
||||
<TableContainer>
|
||||
{ this.props.mod !== undefined && this.props.mod.name.includes("Ultimate Apocalypse") ?
|
||||
<Table sx={{marginTop: "10px"}} size="small" aria-label="a dense table">
|
||||
<Table sx={{marginTop: "10px", textAlign: "center"}} size="small" aria-label="a dense table">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<StyledTableCell><ArmorType
|
||||
@ -335,7 +341,10 @@ class Weapon extends React.Component<IWeaponProps, any> {
|
||||
<StyledTableCell><ArmorType
|
||||
name={ArmorTypeNames.BuildingSuper}/></StyledTableCell>
|
||||
<StyledTableCell><img style={{verticalAlign: "top"}}
|
||||
src="/images/ARM_Morale.webp"/></StyledTableCell>
|
||||
src="/images/ARM_Morale.webp"/>
|
||||
<div style={{width: 20, fontSize: 12, height: 50}}>
|
||||
<i>Morale</i></div>
|
||||
</StyledTableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
@ -386,7 +395,10 @@ class Weapon extends React.Component<IWeaponProps, any> {
|
||||
<StyledTableCell><ArmorType
|
||||
name={ArmorTypeNames.BuildingHigh}/></StyledTableCell>
|
||||
<StyledTableCell><img style={{verticalAlign: "top"}}
|
||||
src="/images/ARM_Morale.webp"/></StyledTableCell>
|
||||
src="/images/ARM_Morale.webp"/>
|
||||
<div style={{width: 20, fontSize: 12, height: 50}}>
|
||||
<i>Morale</i></div>
|
||||
</StyledTableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
@ -415,6 +427,9 @@ class Weapon extends React.Component<IWeaponProps, any> {
|
||||
</TableContainer>
|
||||
<i className="rgdFrom">{weapon.filename}</i>
|
||||
</Grid2>
|
||||
<Grid2 size={12}>
|
||||
{renderAffectedResearches(weapon.affectedResearches, this.props.mod.id, this.props.race.id)}
|
||||
</Grid2>
|
||||
</Grid2>
|
||||
</AccordionDetails>
|
||||
</Accordion></div>
|
||||
|
||||
@ -2,11 +2,13 @@ import Weapon from "./Weapon";
|
||||
import React from "react";
|
||||
import {IWeapon} from "../types/IUnit";
|
||||
import {IMod} from "../types/Imod";
|
||||
import {Irace} from "../types/Irace";
|
||||
|
||||
export interface WeaponSlotProps {
|
||||
hardpoint: number,
|
||||
unitWeapons: Map<number, IWeapon> | undefined,
|
||||
mod: IMod,
|
||||
race: Irace,
|
||||
showOnlyDefault?: boolean ,
|
||||
}
|
||||
|
||||
@ -33,7 +35,7 @@ const WeaponSlot= (props: WeaponSlotProps) => {
|
||||
return (
|
||||
<div>
|
||||
<h3>{header}</h3>
|
||||
<div style={{marginLeft: 20}}><Weapon mod={props.mod} isDefault={true} weapon={firstWeapon}/></div>
|
||||
<div style={{marginLeft: 20}}><Weapon race={props.race} mod={props.mod} isDefault={true} weapon={firstWeapon}/></div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -43,7 +45,7 @@ const WeaponSlot= (props: WeaponSlotProps) => {
|
||||
<h3>{header}</h3>
|
||||
{weaponsSorted.filter(wp => !wp[1].filename.includes("dummy")).map(wp =>
|
||||
|
||||
<div style={{marginLeft: 20}}><Weapon 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]}/></div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -11,120 +11,30 @@ import {
|
||||
TableContainer,
|
||||
TableRow
|
||||
} from "@mui/material";
|
||||
import {IAddonModifier, IBuilding, IBuildingAddon, IBuildingAddonShort} from "../../types/IBuilding";
|
||||
import {IBuilding, IBuildingAddon} 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";
|
||||
import {IMod} from "../../types/Imod";
|
||||
import {IModifier} from "../../types/IModifier";
|
||||
import {getIcon, ModifiersProvidesAddonTable,} from "../ModifiersProvideTable";
|
||||
import Required from "../Required";
|
||||
import {Irace} from "../../types/Irace";
|
||||
|
||||
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\\sight_radius_modifier.lua':
|
||||
return 'Sight';
|
||||
case 'modifiers\\garrison_requisition_modifier.lua':
|
||||
return 'Requisition';
|
||||
case 'modifiers\\faith_max_modifier.lua':
|
||||
return 'Faith max';
|
||||
case 'modifiers\\holy_icon_cost_power.lua':
|
||||
return <span>Next icon cost <img style={{verticalAlign: "top"}} src='/images/Resource_power.gif'/></span>;
|
||||
case 'modifiers\\holy_icon_cost_requisition.lua':
|
||||
return <span>Next icon cost <img style={{verticalAlign: "top"}} src='/images/Resource_requisition.gif'/></span>;
|
||||
case 'modifiers\\enable_hardpoint_02.lua':
|
||||
return 'Weapon slot 2';
|
||||
case 'modifiers\\cost_requisition_modifier.lua':
|
||||
return 'Requisition cost';
|
||||
default:
|
||||
return mt.replace("modifiers\\", "").replace("modifier.lua", "").replace(".lua", "").replaceAll("_", " ");
|
||||
}
|
||||
}
|
||||
|
||||
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\\sight_radius_modifier.lua':
|
||||
return <img style={{verticalAlign: "top"}} src='/images/DETECT_NO.webp'/>;
|
||||
case 'modifiers\\faith_max_modifier.lua':
|
||||
return <img style={{verticalAlign: "top"}} src='/images/Resource_faith.gif'/>;
|
||||
case 'modifiers\\garrison_requisition_modifier.lua':
|
||||
return <img style={{verticalAlign: "top"}} src='/images/Resource_requisition.gif'/>;
|
||||
case 'modifiers\\cost_requisition_modifier.lua':
|
||||
return <img style={{verticalAlign: "top"}} src='/images/Resource_requisition.gif'/>;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
function getChangeDescription(ref: String, v: number) {
|
||||
switch(ref) {
|
||||
case 'type_modifierusagetype\\tp_mod_usage_addition.lua':
|
||||
if(v < 0){
|
||||
return v
|
||||
}else return '+' + v;
|
||||
case 'type_modifierusagetype\\tp_mod_usage_multiplication.lua':
|
||||
return 'x' + v;
|
||||
case 'type_modifierusagetype\\tp_mod_usage_percentage.lua':
|
||||
return '%' + v;
|
||||
case 'type_modifierusagetype\\tp_mod_usage_enable.lua':
|
||||
if(v === 1){
|
||||
return ' enable ';
|
||||
} else {
|
||||
return ' disable ';
|
||||
}
|
||||
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[],
|
||||
modifiers: IModifier[],
|
||||
replacedAddonModifiers: IModifier[],
|
||||
weapons: WeaponHardpoint[],
|
||||
mod: IMod,
|
||||
race: Irace
|
||||
}
|
||||
|
||||
function AddonModifiersProvidesWeapons (props: IAddonModifiersProvidesWeapons) {
|
||||
|
||||
|
||||
function getWeaponByAddonMod(ar: IAddonModifier){
|
||||
function getWeaponByAddonMod(ar: IModifier){
|
||||
|
||||
let hardpoint = Number(ar.reference.replace("modifiers\\default_weapon_modifier_hardpoint", "").replace(".lua", ""));
|
||||
let value = ar.value;
|
||||
@ -133,7 +43,7 @@ function AddonModifiersProvidesWeapons (props: IAddonModifiersProvidesWeapons) {
|
||||
|
||||
let weapon = props.weapons.find(w => w.hardpoint === hardpoint && w.hardpointOrder === 1 + value )?.weapon
|
||||
if (weapon != null){
|
||||
return <WeaponSlot mod={props.mod} unitWeapons={new Map().set(hardpoint, weapon)} hardpoint={hardpoint}/>;
|
||||
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 + " - "
|
||||
}
|
||||
@ -162,43 +72,20 @@ function BuildingAddon(props: IBuildingAddonProps){
|
||||
const building = props.building
|
||||
|
||||
|
||||
const prevAddonModifiers: IAddonModifier[] = (function() {
|
||||
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 [];
|
||||
})()
|
||||
|
||||
function renderRequirementBuilding(requirementBuildings: IBuildingShort[], building: IBuilding) {
|
||||
return requirementBuildings.length > 0 && (
|
||||
<div> Buildings: <img style={{verticalAlign: "top", height: 25}}
|
||||
src={IconUrl + requirementBuildings[0].icon.replaceAll('\\', '/')}/>
|
||||
{" "}<a href={`/mod/${props.mod.id}/race/${building.race.id}/building/${requirementBuildings[0].id}`}>
|
||||
{requirementBuildings[0].name}
|
||||
</a> {requirementBuildings[1] !== undefined && <span>or <img style={{verticalAlign: "top", height: 25}}
|
||||
src={IconUrl + requirementBuildings[1].icon.replaceAll('\\', '/')}/>
|
||||
{" "}<a href={`/mod/${props.mod.id}/race/${building.race.id}/building/${requirementBuildings[1].id}`}>
|
||||
{requirementBuildings[1].name}</a></span> } </div>
|
||||
);
|
||||
}
|
||||
|
||||
function renderRequirementGlobalAddons(rgas: IBuildingAddonShort[], building: IBuilding) {
|
||||
return <div> {rgas.map(rga =>
|
||||
<span> Global addon: <img style={{verticalAlign: "top", height: 25}}
|
||||
src={IconUrl + rga.icon.replaceAll('\\', '/')}/>
|
||||
<a href={`/mod/${props.mod.id}/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>
|
||||
return <div className='addon-research-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('\\', '/')}/>}
|
||||
<img className="sergeantIcon" src={getIcon(addon.icon)}/>
|
||||
{addon.name}
|
||||
</span>
|
||||
</AccordionSummary>
|
||||
@ -242,7 +129,7 @@ function BuildingAddon(props: IBuildingAddonProps){
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer><br/>
|
||||
<AddonModifiersProvidesTable modifiers={addon.addonModifiers}/>
|
||||
<ModifiersProvidesAddonTable modifiers={addon.addonModifiers}/>
|
||||
</Grid2>
|
||||
<Grid2 size={{xs: 12, md: 8}}>
|
||||
<div style={{whiteSpace: "pre-wrap"}}>
|
||||
@ -251,32 +138,11 @@ function BuildingAddon(props: IBuildingAddonProps){
|
||||
</Grid2>
|
||||
{addon.addonModifiers !== null &&
|
||||
<Grid2 size={{xs: 12, md: 12}}>
|
||||
<AddonModifiersProvidesWeapons mod={props.mod} modifiers={addon.addonModifiers} replacedAddonModifiers={prevAddonModifiers} weapons={building.weapons}/>
|
||||
<AddonModifiersProvidesWeapons race={building.race} mod={props.mod} 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> Population: <img style={{verticalAlign: "top", height: 25}}
|
||||
src="/images/Resource_orksquadcap.gif"/>
|
||||
{addon.addonRequirement.requiredTotalPop}</div>
|
||||
}
|
||||
{addon.addonRequirement.requireAddon !== null &&
|
||||
<div> Addon: <img style={{verticalAlign: "top", height: 25}}
|
||||
src={IconUrl + addon.addonRequirement.requireAddon.icon.replaceAll('\\', '/')}/>
|
||||
<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> Building: <img style={{verticalAlign: "top", height: 25}}
|
||||
src={IconUrl + b.icon.replaceAll('\\', '/')}/>
|
||||
<a href= {'/mod/'+ props.mod.id +'/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)}
|
||||
<Required requirement={addon.addonRequirement} building={building}/>
|
||||
</Grid2>}
|
||||
</Grid2>
|
||||
<i className="rgdFrom">{addon.filename}</i>
|
||||
|
||||
124
src/classes/building/Research.tsx
Normal file
124
src/classes/building/Research.tsx
Normal file
@ -0,0 +1,124 @@
|
||||
import {IMod} from "../../types/Imod";
|
||||
import {IResearch} from "../../types/IResearch";
|
||||
import {
|
||||
Accordion,
|
||||
AccordionDetails,
|
||||
AccordionSummary,
|
||||
Grid2,
|
||||
Paper,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableRow
|
||||
} from "@mui/material";
|
||||
import {ExpandMore} from "@mui/icons-material";
|
||||
import {getIcon, ModifiersProvidesResearchTable} from "../ModifiersProvideTable";
|
||||
import AvTimerOutlinedIcon from "@mui/icons-material/AvTimer";
|
||||
import Required from "../Required";
|
||||
import React from "react";
|
||||
import {IBuilding} from "../../types/IBuilding";
|
||||
import {IResearchShort} from "../../types/IResearchShort";
|
||||
|
||||
|
||||
interface IResearchProps {
|
||||
research: IResearch,
|
||||
building: IBuilding,
|
||||
mod: IMod,
|
||||
}
|
||||
|
||||
function ResearchFull(props: IResearchProps){
|
||||
|
||||
const research = props.research
|
||||
const building = props.building
|
||||
|
||||
return <div className='addon-research-accordion' id={"research-" + research.id}><Accordion>
|
||||
<AccordionSummary
|
||||
expandIcon={<ExpandMore/>}
|
||||
aria-controls="panel1-content"
|
||||
>
|
||||
<span style={{fontSize: 20}}>
|
||||
<img className="sergeantIcon" src={getIcon(research.icon)}/>
|
||||
{research.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">
|
||||
{research.costRequisition > 0 &&
|
||||
<span> <img style={{verticalAlign: "top"}}
|
||||
src="/images/Resource_requisition.gif"/>
|
||||
{research.costRequisition.toFixed(0)}</span>}
|
||||
{research.costPower > 0 && <span> <img style={{verticalAlign: "top"}}
|
||||
src="/images/Resource_power.gif"/>
|
||||
{research.costPower.toFixed(0)}</span>}
|
||||
{(research.costPopulation !== undefined && research.costPopulation > 0) &&
|
||||
<span> <img style={{verticalAlign: "top"}}
|
||||
src="/images/Resource_orksquadcap.gif"/>
|
||||
{research.costPopulation.toFixed(0)}</span>}
|
||||
{(research.costFaith !== undefined && research.costFaith > 0) &&
|
||||
<span> <img style={{verticalAlign: "top"}}
|
||||
src="/images/Resource_faith.gif"/>
|
||||
{research.costFaith}</span>}
|
||||
{(research.costSouls !== undefined && research.costSouls > 0) &&
|
||||
<span> <img style={{verticalAlign: "top"}}
|
||||
src="/images/Resource_souls.gif"/>
|
||||
{research.costSouls.toFixed(0)}</span>}
|
||||
{(research.costTime !== undefined && research.costTime > 0) &&
|
||||
<span> <AvTimerOutlinedIcon
|
||||
style={{verticalAlign: "top", fontSize: "18px"}}/>
|
||||
{research.costTime}s</span>}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer><br/>
|
||||
</Grid2>
|
||||
<Grid2 size={{xs: 12, md: 8}}>
|
||||
<div style={{whiteSpace: "pre-wrap"}}>
|
||||
{research.description}
|
||||
</div>
|
||||
|
||||
</Grid2>
|
||||
<Grid2 size={{xs: 12, md: 12}}>
|
||||
<ModifiersProvidesResearchTable modifiers={research.modifiers} research={research} race={building.race}/>
|
||||
</Grid2>
|
||||
{research.requirements !== null &&
|
||||
<Grid2 size={{xs: 12, md: 12}}>
|
||||
<Required requirement={research.requirements} building={building}/>
|
||||
</Grid2>}
|
||||
</Grid2>
|
||||
<i className="rgdFrom">{research.filename}</i>
|
||||
</AccordionDetails>
|
||||
</Accordion></div>
|
||||
|
||||
}
|
||||
|
||||
export function renderAffectedResearches(researches: IResearchShort[], modId: number, raceId: string) {
|
||||
|
||||
function researchLink(rs: IResearchShort) {
|
||||
return <span><img style={{verticalAlign: "top", height: 25}}
|
||||
src={getIcon(rs.icon)}/>
|
||||
<a href={`/mod/${modId}/race/${raceId}/building/${rs.buildingId}#research-${rs.id}`}>
|
||||
{rs.name}
|
||||
</a></span>
|
||||
}
|
||||
|
||||
return <div> {researches.map(rs =>
|
||||
rs.buildingId == null ? <span></span> :
|
||||
<span>Research affect: {researchLink(rs)}<br/></span>
|
||||
)}</div>
|
||||
}
|
||||
|
||||
|
||||
export default ResearchFull;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
.addon-accordion{
|
||||
.addon-research-accordion{
|
||||
margin-top: 10px;
|
||||
scroll-margin-top: 15px;
|
||||
}
|
||||
@ -6,5 +6,5 @@
|
||||
|
||||
|
||||
.selected-addon div {
|
||||
background-color: antiquewhite;
|
||||
background-color: #fafaf2;
|
||||
}
|
||||
@ -3,7 +3,18 @@ import React from "react";
|
||||
import {withRouter} from "../core/withrouter";
|
||||
import {IWeapon} from "../types/IUnit";
|
||||
import '../css/Building.css'
|
||||
import {Button, Grid2, Paper, Table, TableBody, TableCell, TableContainer, TableRow} from "@mui/material";
|
||||
import {
|
||||
Button,
|
||||
Grid2,
|
||||
Link,
|
||||
ListItem,
|
||||
Paper,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableRow
|
||||
} from "@mui/material";
|
||||
import {ArrowBack} from "@mui/icons-material";
|
||||
import ArmorType from "../classes/ArmorType";
|
||||
import AvTimerOutlinedIcon from '@mui/icons-material/AvTimer';
|
||||
@ -13,12 +24,25 @@ import {IMod} from "../types/Imod";
|
||||
import {IBuilding} from "../types/IBuilding";
|
||||
import Vision from "../classes/Vision";
|
||||
import BuildingAddon from "../classes/building/BuildingAddon";
|
||||
import {IUnitShort} from "../types/IUnitShort";
|
||||
import Research, {renderAffectedResearches} from "../classes/building/Research";
|
||||
|
||||
interface UintPageState {
|
||||
building: IBuilding,
|
||||
mod: IMod,
|
||||
}
|
||||
|
||||
function Unit (unit: IUnitShort, modId: number, raceId: String) {
|
||||
|
||||
return (<Link href={"/mod/" + modId + "/race/" + raceId + "/unit/" + unit.id}><ListItem>
|
||||
{unit.icon && <img className="unitIcon" src={IconUrl + unit.icon.replaceAll('\\', '/')}/> }
|
||||
{unit.name}
|
||||
{unit.canDetect && <span> <img style={{verticalAlign: "top"}}
|
||||
src="/images/DETECT_YES.webp"/></span>}
|
||||
|
||||
</ListItem></Link>)
|
||||
}
|
||||
|
||||
|
||||
function Building(building: IBuilding, mod: IMod) {
|
||||
|
||||
@ -36,13 +60,16 @@ function Building(building: IBuilding, mod: IMod) {
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
var buildingName = building.name;
|
||||
if(building.name == null){
|
||||
buildingName = building.filename.replaceAll('_', ' ').replace('.rgd', '');
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>{mod.name} ({mod.version})</h1>
|
||||
<h2>{building.icon &&
|
||||
<img className="unitIcon" src={IconUrl + building.icon.replaceAll('\\', '/')}/>} {building.name} </h2>
|
||||
<img className="unitIcon" src={IconUrl + building.icon.replaceAll('\\', '/')}/>} {buildingName} </h2>
|
||||
|
||||
<Grid2 container spacing={2}>
|
||||
<Grid2 size={{xs: 12, md: 4}}>
|
||||
@ -103,7 +130,8 @@ function Building(building: IBuilding, mod: IMod) {
|
||||
>
|
||||
<TableCell component="th" scope="row">Armor type</TableCell>
|
||||
<TableCell component="th" scope="row">
|
||||
<ArmorType name={building.armorType.name}/>
|
||||
<ArmorType name={building.armorType.name} compact={false}/>
|
||||
{building.armorType2 && <span><br/><ArmorType name={building.armorType2.name} compact={false}/></span> }
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow
|
||||
@ -142,16 +170,31 @@ function Building(building: IBuilding, mod: IMod) {
|
||||
{building.description}
|
||||
</div>
|
||||
</Grid2>
|
||||
{building.units.length > 0 && <Grid2 size={12}>
|
||||
<h3>Unit production</h3>
|
||||
{building.units.map(unit =>
|
||||
Unit(unit, mod.id, building.race.id)
|
||||
)}
|
||||
</Grid2>}
|
||||
{building.addons.length > 0 && <Grid2 size={12}>
|
||||
<h3>Addons</h3>
|
||||
{building.addons.map(b =>
|
||||
<BuildingAddon mod={mod} addon={b} building={building}/>
|
||||
)}
|
||||
</Grid2> }
|
||||
{building.researches.length > 0 && <Grid2 size={12}>
|
||||
<h3>Researches</h3>
|
||||
{building.researches.map(r =>
|
||||
<Research mod={mod} research={r} building={building}/>
|
||||
)}
|
||||
</Grid2> }
|
||||
<Grid2 size={12}>
|
||||
{[...mapBuildingWeapons.keys()].sort(function (a, b) {
|
||||
return a - b;
|
||||
}).map(h => <WeaponSlot mod={mod} showOnlyDefault={true} unitWeapons={mapBuildingWeapons.get(h)} hardpoint={h}/>)}
|
||||
}).map(h => <WeaponSlot race={building.race} mod={mod} showOnlyDefault={true} unitWeapons={mapBuildingWeapons.get(h)} hardpoint={h}/>)}
|
||||
</Grid2>
|
||||
<Grid2 size={12}>
|
||||
{renderAffectedResearches(building.affectedResearches, mod.id, building.race.id)}
|
||||
</Grid2>
|
||||
</Grid2>
|
||||
<i className="rgdFrom">{building.filename}</i>
|
||||
@ -162,7 +205,6 @@ function Building(building: IBuilding, mod: IMod) {
|
||||
|
||||
function goToAddon(addonHash: string) {
|
||||
let addonId = addonHash.replace("#", "");
|
||||
console.log(addonId);
|
||||
[].forEach.call(document.querySelectorAll('div'), function (el: HTMLElement) {
|
||||
el?.classList?.remove('selected-addon');
|
||||
});
|
||||
@ -170,6 +212,15 @@ function goToAddon(addonHash: string) {
|
||||
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> {
|
||||
|
||||
@ -188,6 +239,7 @@ class BuildingPage extends React.Component<any, UintPageState> {
|
||||
mod: modData
|
||||
});
|
||||
goToAddon(window.location.hash);
|
||||
goToResearch(window.location.hash);
|
||||
}
|
||||
|
||||
render() {
|
||||
@ -207,4 +259,4 @@ class BuildingPage extends React.Component<any, UintPageState> {
|
||||
|
||||
export default withRouter(BuildingPage);
|
||||
|
||||
export { goToAddon };
|
||||
export { goToAddon, goToResearch };
|
||||
@ -21,6 +21,8 @@ function Mods (mods: IMod[]) {
|
||||
function Mod (modName: String) {
|
||||
let sameMods = mapWithModVersions.get(modName) ?? []
|
||||
|
||||
let lastBeta = sameMods.filter((m) => m.isBeta).reverse()[0]
|
||||
|
||||
return(
|
||||
<div>
|
||||
<h1>{modName}</h1>
|
||||
@ -28,9 +30,9 @@ function Mods (mods: IMod[]) {
|
||||
{sameMods.filter((m) => !m.isBeta).map(mod =>
|
||||
<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 &&
|
||||
sameMods.filter((m) => m.isBeta).map(mod =>
|
||||
<ul><NavLink state={mod.id} to= {"/mod/" + mod.id} >{mod.version}</NavLink></ul>)}
|
||||
{lastBeta != null &&
|
||||
<ul><NavLink state={lastBeta.id} to={"/mod/" + lastBeta.id}>{lastBeta.version}</NavLink></ul>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -62,7 +62,7 @@ function UnitSmall (unit: IUnitShort, modId: number, raceId: String) {
|
||||
return (<Link href={"/mod/" + modId + "/race/" + raceId + "/unit/" + unit.id}>
|
||||
{unit.icon && <img className="unitIconSmall" src={IconUrl + unit.icon.replaceAll('\\', '/')}/>}
|
||||
<span style={{fontSize: 12}}>{unitName}</span>
|
||||
{unit.canDetect && <span> <img style={{verticalAlign: "top"}}
|
||||
{unit.canDetect && <span> <img
|
||||
src="/images/DETECT_YES.webp"/></span>}<br/></Link>)
|
||||
}
|
||||
|
||||
@ -140,6 +140,7 @@ class Units extends React.Component<UnitsProps, UnitsState> {
|
||||
<h3>All units</h3>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<Grid2 container spacing={2}>
|
||||
<Grid2 size= {{xs: 12, md: 4}}>
|
||||
<h3>Infantry</h3>
|
||||
{this.state.units.infantry.map(unit => Unit(unit, this.props.modId, this.props.raceId))}
|
||||
@ -156,6 +157,7 @@ class Units extends React.Component<UnitsProps, UnitsState> {
|
||||
{this.state.units.support.map(unit => Unit(unit, this.props.modId, this.props.raceId))}
|
||||
</List>
|
||||
</Grid2>
|
||||
</Grid2>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
</Grid2><br/>
|
||||
|
||||
@ -24,6 +24,10 @@ import WeaponSlot from "../classes/WeaponSlot";
|
||||
import UnitsTable from "../classes/UnitsTable";
|
||||
import {IMod} from "../types/Imod";
|
||||
import Vision from "../classes/Vision";
|
||||
import {IResearchRequirements} from "../types/IResearchRequirements";
|
||||
import {getIcon} from "../classes/Required";
|
||||
import {IResearchShort} from "../types/IResearchShort";
|
||||
import {renderAffectedResearches} from "../classes/building/Research";
|
||||
|
||||
interface UintPageState {
|
||||
unit: IUnit,
|
||||
@ -188,7 +192,9 @@ function Unit(unit: IUnit, mod: IMod) {
|
||||
>
|
||||
<TableCell component="th" scope="row">Armor type</TableCell>
|
||||
<TableCell component="th" scope="row">
|
||||
<ArmorType name={unit.armorType.name}/>
|
||||
<ArmorType name={unit.armorType.name} compact={false}/>
|
||||
{unit.armorType2 && <span style={{fontSize: 12}} ><br/><i>after upgrade can become:<br/><ArmorType
|
||||
name={unit.armorType2.name} compact={false}/></i></span> }
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow
|
||||
@ -200,7 +206,7 @@ function Unit(unit: IUnit, mod: IMod) {
|
||||
src="/images/Health_icon.webp"/>
|
||||
{unit.health} {unit.healthRegeneration > 0 &&
|
||||
<span>+{unit.healthRegeneration}/s</span>}
|
||||
{unit.armour !== undefined && unit.armour > 0 && <span><img style={{height: 20, verticalAlign: "top"}} src="/images/defence.png"/>{unit.armour} </span> }
|
||||
{unit.armour !== undefined && unit.armour !== 0 && <span><img style={{height: 20, verticalAlign: "top"}} src="/images/defence.png"/>{unit.armour} </span> }
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow
|
||||
@ -243,11 +249,11 @@ function Unit(unit: IUnit, mod: IMod) {
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
}
|
||||
{unit.repairSpeed !== undefined && unit.repairSpeed !== null &&
|
||||
{unit.repairSpeed !== undefined && unit.repairSpeed !== null && unit.repairCostPercent !== null &&
|
||||
<TableRow>
|
||||
<TableCell>Repair speed</TableCell>
|
||||
<TableCell>Repair</TableCell>
|
||||
<TableCell>
|
||||
{unit.repairSpeed}
|
||||
{unit.repairSpeed} hp/s; {unit.repairCostPercent}% cost
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
}
|
||||
@ -271,7 +277,7 @@ function Unit(unit: IUnit, mod: IMod) {
|
||||
<SergeantShort name={s.name} icon={s.icon} canDetect={s.detectRadius > 0}/>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<Sergeant mod={mod} sergeant={s}/>
|
||||
<Sergeant mod={mod} sergeant={s} race={unit.race}/>
|
||||
<hr/>
|
||||
</AccordionDetails>
|
||||
|
||||
@ -280,7 +286,10 @@ function Unit(unit: IUnit, mod: IMod) {
|
||||
<Grid2 size={12}>
|
||||
{[...mapWithUnitWeapons.keys()].sort(function (a, b) {
|
||||
return a - b;
|
||||
}).map(h => <WeaponSlot mod={mod} unitWeapons={mapWithUnitWeapons.get(h)} hardpoint={h}/>)}
|
||||
}).map(h => <WeaponSlot race={unit.race} mod={mod} unitWeapons={mapWithUnitWeapons.get(h)} hardpoint={h}/>)}
|
||||
</Grid2>
|
||||
<Grid2 size={12}>
|
||||
{renderAffectedResearches(unit.affectedResearches, mod.id, unit.race.id)}
|
||||
</Grid2>
|
||||
</Grid2>
|
||||
<i className="rgdFrom">{unit.filename}</i>
|
||||
@ -290,6 +299,8 @@ function Unit(unit: IUnit, mod: IMod) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
class UnitPage extends React.Component<any, UintPageState> {
|
||||
|
||||
|
||||
|
||||
@ -2,15 +2,15 @@ enum ArmorTypeValues {
|
||||
InfantryLow = 'Infantry Low',
|
||||
InfantryMedium = 'Infantry Medium',
|
||||
InfantryHigh = 'Infantry High',
|
||||
InfantryHeavyMedium = 'Infantry Heavy Medium',
|
||||
InfantryHeavyHigh = 'Infantry Heavy High',
|
||||
Commander = 'Commander',
|
||||
InfantryHeavyMedium = 'Infantry H.Med.',
|
||||
InfantryHeavyHigh = 'Infantry H.High',
|
||||
Commander = 'Infantry Com.',
|
||||
VehicleLow = 'Vehicle Low',
|
||||
VehicleMedium = 'Vehicle Medium',
|
||||
VehicleHigh = 'Vehicle High',
|
||||
LivingMetal = 'Living Metal',
|
||||
Titan = 'Titan',
|
||||
Air = 'Air',
|
||||
Air = 'Vehicle Air',
|
||||
BuildingLow = 'Building Low',
|
||||
BuildingMedium = 'Building Medium',
|
||||
BuildingHigh = 'Building High',
|
||||
|
||||
23
src/types/IAffectedEntity.tsx
Normal file
23
src/types/IAffectedEntity.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
export interface IAffectedEntity {
|
||||
id: number
|
||||
name: string
|
||||
icon: string
|
||||
filename: string
|
||||
}
|
||||
|
||||
export interface ISergeantUnitShortDto {
|
||||
id: number
|
||||
name: string
|
||||
icon: string
|
||||
filename: string
|
||||
unit: IAffectedEntity
|
||||
}
|
||||
|
||||
export interface IWeaponUnitShortDto {
|
||||
id: number
|
||||
name: string
|
||||
filename: string
|
||||
units: IAffectedEntity[]
|
||||
sergeants: ISergeantUnitShortDto[]
|
||||
buildings: IAffectedEntity[]
|
||||
}
|
||||
@ -1,7 +1,11 @@
|
||||
import {Irace} from "./Irace";
|
||||
import {IArmorType} from "./IArmorType";
|
||||
import {WeaponHardpoint} from "./IUnit";
|
||||
import {IBuildingShort} from "./IBuildingShort";
|
||||
import {IUnitShort} from "./IUnitShort";
|
||||
import {IModifier} from "./IModifier";
|
||||
import {IRequirement} from "./IRequirement";
|
||||
import {IResearch} from "./IResearch";
|
||||
import {IResearchShort} from "./IResearchShort";
|
||||
|
||||
export interface IBuilding {
|
||||
id: number
|
||||
@ -30,6 +34,9 @@ export interface IBuilding {
|
||||
modId: number
|
||||
weapons: WeaponHardpoint[]
|
||||
addons: IBuildingAddon[]
|
||||
researches: IResearch[]
|
||||
units: IUnitShort[]
|
||||
affectedResearches: IResearchShort[],
|
||||
}
|
||||
|
||||
export interface IBuildingAddon {
|
||||
@ -43,8 +50,8 @@ export interface IBuildingAddon {
|
||||
addonCostFaith: number;
|
||||
addonCostSouls: number;
|
||||
addonCostTime: number;
|
||||
addonModifiers: IAddonModifier[];
|
||||
addonRequirement: IAddonRequirement;
|
||||
addonModifiers: IModifier[];
|
||||
addonRequirement: IRequirement;
|
||||
icon?: string;
|
||||
}
|
||||
|
||||
@ -54,19 +61,3 @@ export interface IBuildingAddonShort {
|
||||
name: string;
|
||||
icon: string;
|
||||
}
|
||||
|
||||
export interface IAddonRequirement {
|
||||
requirementBuildings: IBuildingShort[];
|
||||
requirementBuildingsEither: IBuildingShort[];
|
||||
requirementsGlobalAddons: IBuildingAddonShort[];
|
||||
replaceWhenDone: Boolean;
|
||||
requireAddon: IBuildingAddonShort;
|
||||
requiredTotalPop?: number;
|
||||
}
|
||||
|
||||
export interface IAddonModifier {
|
||||
id: number;
|
||||
reference: string;
|
||||
usageType: string;
|
||||
value: number;
|
||||
}
|
||||
8
src/types/IModifier.tsx
Normal file
8
src/types/IModifier.tsx
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
export interface IModifier {
|
||||
id: number;
|
||||
reference: string;
|
||||
usageType: string;
|
||||
target: string;
|
||||
value: number;
|
||||
}
|
||||
13
src/types/IRequirement.tsx
Normal file
13
src/types/IRequirement.tsx
Normal file
@ -0,0 +1,13 @@
|
||||
import {IBuildingShort} from "./IBuildingShort";
|
||||
import {IBuildingAddonShort} from "./IBuilding";
|
||||
import {IResearchRequirements} from "./IResearchRequirements";
|
||||
|
||||
export interface IRequirement {
|
||||
requirementBuildings: IBuildingShort[];
|
||||
requirementBuildingsEither: IBuildingShort[];
|
||||
requirementsGlobalAddons: IBuildingAddonShort[];
|
||||
requirementResearches: IResearchRequirements[];
|
||||
replaceWhenDone: Boolean;
|
||||
requireAddon: IBuildingAddonShort;
|
||||
requiredTotalPop?: number;
|
||||
}
|
||||
24
src/types/IResearch.tsx
Normal file
24
src/types/IResearch.tsx
Normal file
@ -0,0 +1,24 @@
|
||||
import {IModifier} from "./IModifier";
|
||||
import {IRequirement} from "./IRequirement";
|
||||
import {IAffectedEntity, ISergeantUnitShortDto, IWeaponUnitShortDto} from "./IAffectedEntity";
|
||||
|
||||
export interface IResearch {
|
||||
id: number
|
||||
name: string
|
||||
filename: string
|
||||
description: string
|
||||
costRequisition: number
|
||||
costPower: number
|
||||
costPopulation: number
|
||||
costFaith: number
|
||||
costSouls: number
|
||||
costTime: number
|
||||
icon: string
|
||||
modId: number
|
||||
affectedUnits: IAffectedEntity[]
|
||||
affectedSergeants: ISergeantUnitShortDto[]
|
||||
affectedBuildings: IAffectedEntity[]
|
||||
affectedWeapons: IWeaponUnitShortDto[]
|
||||
requirements: IRequirement
|
||||
modifiers: IModifier[]
|
||||
}
|
||||
6
src/types/IResearchRequirements.tsx
Normal file
6
src/types/IResearchRequirements.tsx
Normal file
@ -0,0 +1,6 @@
|
||||
import {IResearchShort} from "./IResearchShort";
|
||||
|
||||
export interface IResearchRequirements {
|
||||
researchShortDto: IResearchShort,
|
||||
researchMustNotBeComplete: Boolean,
|
||||
}
|
||||
6
src/types/IResearchShort.tsx
Normal file
6
src/types/IResearchShort.tsx
Normal file
@ -0,0 +1,6 @@
|
||||
export interface IResearchShort {
|
||||
id: string;
|
||||
name: string;
|
||||
icon: string;
|
||||
buildingId: number;
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
import {Irace} from "./Irace";
|
||||
import {IArmorType} from "./IArmorType";
|
||||
import {IResearchShort} from "./IResearchShort";
|
||||
|
||||
export interface IUnitResponse {
|
||||
race: string
|
||||
@ -53,6 +54,7 @@ export interface IUnit {
|
||||
modId: number
|
||||
sergeants: ISergeant[]
|
||||
weapons: WeaponHardpoint[]
|
||||
affectedResearches: IResearchShort[],
|
||||
}
|
||||
|
||||
export interface ISergeant {
|
||||
@ -81,6 +83,7 @@ export interface ISergeant {
|
||||
detectRadius: number
|
||||
icon: string
|
||||
weapons: WeaponHardpoint[]
|
||||
affectedResearches: IResearchShort[],
|
||||
}
|
||||
|
||||
|
||||
@ -118,6 +121,7 @@ export interface IWeapon {
|
||||
icon: string
|
||||
modId: number
|
||||
weaponArmorPiercing: IWeaponPiercing[]
|
||||
affectedResearches: IResearchShort[],
|
||||
}
|
||||
|
||||
export interface IWeaponPiercing {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user