Units wiki

This commit is contained in:
v.holodov
2025-01-07 15:39:00 +03:00
parent 4a5101fb6a
commit 27308c2c88
54 changed files with 797 additions and 12339 deletions
+54
View File
@@ -0,0 +1,54 @@
import {AvailableMods, AvailableRacesPart} from "../core/api";
import React, {useEffect, useRef, useState} from "react";
import {NavLink, useLocation, useParams} from "react-router-dom";
import {withRouter} from "../core/withrouter";
import {IMod} from "../types/Imod";
import {Irace} from "../types/Irace";
interface ModPageState {
mod: IMod,
races: Irace[],
modId: Number,
}
class ModPage extends React.Component<any, ModPageState> {
constructor(props: any) {
super(props);
console.log(this.props.match.params.id);
this.setState({
modId : this.props.match.params.id
});
}
async componentDidMount() {
const responseMod = await fetch(AvailableMods + "/" + this.props.match.params.id);
const modData: IMod = await responseMod.json();
console.log(modData);
this.setState({
mod : modData
});
const response = await fetch(AvailableRacesPart + "/mod/" + this.props.match.params.id);
const racesData: Irace[] = await response.json();
this.setState({
races : racesData
});
}
render() {
if(this.state != null && this.state.races != null ){
return <div><h1>{this.state.mod.name} ({this.state.mod.version})</h1>
{this.state.races.map(race => <ul><NavLink state={race.id} to= {"/mod/" + this.state.mod.id + "/race/" + race.id} >{race.name}</NavLink></ul>)}
</div>;
} else {
return "";
}
}
}
export default withRouter(ModPage);
+67
View File
@@ -0,0 +1,67 @@
import {AvailableMods} from "../core/api";
import React, {useEffect, useState} from "react";
import {NavLink} from "react-router-dom";
import {IMod} from "../types/Imod";
function Mods (mods: IMod[]) {
let mapWithModVersions: Map<String, IMod[]> = new Map();
mods.forEach( mod => {
const versionList = mapWithModVersions.get(mod.name)
if(versionList == null){
mapWithModVersions.set(mod.name, new Array(mod))
} else {
versionList.push(mod)
}
})
function Mod (modName: String) {
let sameMods = mapWithModVersions.get(modName) ?? []
return(
<div>
<h1>{modName}</h1>
{sameMods.map(mod => <ul><NavLink state={mod.id} to= {"/mod/" + mod.id} >{mod.version}</NavLink></ul>)}
</div>
)
}
mapWithModVersions.keys()
return(
[...mapWithModVersions.keys()].map(m => Mod(m))
)
}
interface ModsPageState {
mods: IMod[]
}
class ModsPage extends React.Component<any, ModsPageState> {
constructor({props}: { props: any }) {
super(props);
this.state = {
mods: []
}
}
async componentDidMount() {
const response = await fetch(AvailableMods);
const data: IMod[] = await response.json();
console.log(data);
this.setState({
mods : data
});
}
render() {
return <div>{Mods(this.state.mods)}</div>;
}
}
export default ModsPage
+252
View File
@@ -0,0 +1,252 @@
import {AvailableMods, AvailableRacesPart, AvailableUnits, IconUrl} from "../core/api";
import React, {useState} from "react";
import {withRouter} from "../core/withrouter";
import {IMod} from "../types/Imod";
import {Irace} from "../types/Irace";
import {IUnit, IUnitResponse} from "../types/IUnit";
import '../css/Unit.css'
import {
Accordion, AccordionDetails,
AccordionSummary,
Button,
ButtonGroup, Grid2, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow,
ToggleButton,
ToggleButtonClassKey,
ToggleButtonGroup, Typography
} from "@mui/material";
import {ArrowDropDown} from "@mui/icons-material";
import ArmorType from "../classes/ArmorType";
import Item from "../classes/Item";
interface RacePageState {
mod: IMod,
modId: Number,
race: Irace,
units: IUnitResponse,
}
function humanReadableUnitName(unit: string) {
const firstUpper = String(unit).charAt(0).toUpperCase() + String(unit).slice(1);
return firstUpper.replaceAll('_', ' ').replace('.rgd', '');
}
function Unit (unit: IUnit) {
const morale = (unit.moraleMax !== null) ? <span>
<img style={{verticalAlign: "top"}} src="/images/ARM_Morale.webp"/>&nbsp;{unit.moraleMax}
+{unit.moraleRegeneration}/s
{unit.moraleDeathPenalty > 0 && <span> <img style={{verticalAlign: "top"}} src="/images/Kills_icon.webp"/> -{unit.moraleDeathPenalty}</span>}
</span> : "-"
const detect = unit.detectRadius > 0 ? <span>&nbsp;<img style={{verticalAlign: "top"}}
src="/images/DETECT_YES.webp"/> {unit.detectRadius}</span> :
<span>&nbsp;<img style={{verticalAlign: "top"}}
src="/images/DETECT_NO.webp"/></span>
return (
<Accordion>
<AccordionSummary
expandIcon={<ArrowDropDown/>}
aria-controls="panel1-content"
id={unit.filename}
>
<img className="unitIcon" src={IconUrl + unit.icon.replaceAll('\\', '/')}/>
<h2> {unit.name}</h2>
{unit.detectRadius > 0 && <span>&nbsp;<img style={{verticalAlign: "top"}}
src="/images/DETECT_YES.webp"/></span>}
</AccordionSummary>
<AccordionDetails>
<Grid2 container spacing={2}>
<Grid2 size={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">
{unit.buildCostRequisition > 0 && <span>&nbsp;<img style={{verticalAlign: "top"}}
src="/images/Resource_requisition.gif"/>&nbsp;
{unit.buildCostRequisition}</span>}
{unit.buildCostPower > 0 && <span>&nbsp;<img style={{verticalAlign: "top"}}
src="/images/Resource_power.gif"/>&nbsp;
{unit.buildCostPower}</span>}
{unit.capInfantry > 0 && <span>&nbsp;<img style={{verticalAlign: "top"}}
src="/images/Resource_cap_infantry.gif"/>&nbsp;
{unit.capInfantry}</span>}
{unit.capSupport > 0 && <span>&nbsp;<img style={{verticalAlign: "top"}}
src="/images/Resource_cap_vehicle.gif"/>&nbsp;
{unit.capSupport}</span>}
</TableCell>
</TableRow>
<TableRow
sx={{'&:last-child td, &:last-child th': {border: 0}}}
>
<TableCell component="th" scope="row">armor type</TableCell>
<TableCell component="th" scope="row">
<ArmorType value={unit.armorType.name}/>
</TableCell>
</TableRow>
<TableRow
sx={{'&:last-child td, &:last-child th': {border: 0}}}
>
<TableCell component="th" scope="row">health</TableCell>
<TableCell component="th" scope="row">
<span><img style={{verticalAlign: "top"}}
src="/images/Health_icon.webp"/>&nbsp;
{unit.health} {unit.healthRegeneration > 0 &&
<span>+{unit.healthRegeneration}/s</span>} </span>
</TableCell>
</TableRow>
<TableRow
sx={{'&:last-child td, &:last-child th': {border: 0}}}
>
<TableCell component="th" scope="row">move speed</TableCell>
<TableCell component="th" scope="row">
{unit.moveSpeed}
</TableCell>
</TableRow>
<TableRow
sx={{'&:last-child td, &:last-child th': {border: 0}}}
>
<TableCell component="th" scope="row">morale</TableCell>
<TableCell component="th" scope="row">
{morale}
</TableCell>
</TableRow>
<TableRow
sx={{'&:last-child td, &:last-child th': {border: 0}}}
>
<TableCell component="th" scope="row">detect</TableCell>
<TableCell component="th" scope="row">
{detect}
</TableCell>
</TableRow>
</TableBody>
</Table>
</TableContainer>
</Grid2>
<Grid2 size={8}>
<div style={{whiteSpace: "pre-wrap"}} >
{unit.description}
</div>
</Grid2>
</Grid2>
<i>{unit.filename}</i>
</AccordionDetails>
</Accordion>)
}
interface UnitsState {
selectedUnits: String | null,
}
class Units extends React.Component<IUnitResponse, UnitsState> {
constructor(props: any) {
super(props);
this.state = ({
selectedUnits: 'infantry'
});
}
handleChange = (e: React.MouseEvent, newUnitType: String | null) => {
this.setState({
selectedUnits: newUnitType
});
{this.props.units.map(unit => Unit(unit))}
}
render () {
let unitsToRender: IUnit[] = [];
if(this.state.selectedUnits === 'infantry'){
unitsToRender = this.props.units.filter(unit => unit.capInfantry > 0)
} else if (this.state.selectedUnits === 'tech'){
unitsToRender = this.props.units.filter(unit => unit.capSupport > 0)
} else {
unitsToRender = this.props.units.filter(unit => unit.capSupport == 0 && unit.capInfantry == 0)
}
if (this.state) {
return (<div>
<ToggleButtonGroup
color="primary"
exclusive
onChange={this.handleChange}
value={this.state.selectedUnits}
aria-label="Platform"
>
<ToggleButton value="infantry">Infantry</ToggleButton>
<ToggleButton value="tech">Tech</ToggleButton>
<ToggleButton value="support">Support</ToggleButton>
</ToggleButtonGroup>
<div id = 'filtered-units'>
{unitsToRender.map(unit => Unit(unit))}
</div>
</div>)
} else {
return "";
}
}
}
class RacePage extends React.Component<any, RacePageState> {
constructor(props: any) {
super(props);
console.log(this.props.match.params.id);
this.setState({
modId: this.props.match.params.id
});
}
async componentDidMount() {
const responseMod = await fetch(AvailableMods + "/" + this.props.match.params.modId);
const modData: IMod = await responseMod.json();
this.setState({
mod: modData
});
const response = await fetch(AvailableRacesPart + "/" + this.props.match.params.raceId);
const racesData: Irace = await response.json();
this.setState({
race : racesData
});
const unitsResponse = await fetch(AvailableUnits + "/" + this.state.mod.id + "/" + this.props.match.params.raceId);
const unitsData: IUnitResponse = await unitsResponse.json();
console.log(unitsData);
this.setState({
units : unitsData
});
}
render() {
if(this.state != null && this.state.units != null ){
return <div><h1>{this.state.mod.name} ({this.state.mod.version}) - {this.state.race.name}</h1>
<Units race={this.state.race.name} units={this.state.units.units}/>
</div>;
} else {
return "";
}
}
}
export default withRouter(RacePage);