'use client'; import React, { useEffect, useState } from 'react'; import { Box, Container, Divider, Grid2, Link, ListItem, Paper, Table, TableBody, TableCell, TableRow, Tooltip, Typography, LinearProgress, Theme, } from '@mui/material'; import { styled } from '@mui/material/styles'; import { useTheme } from '@mui/material/styles'; import { useParams } from 'next/navigation'; import { ArrowBack } from '@mui/icons-material'; import AvTimerOutlinedIcon from '@mui/icons-material/AvTimer'; import { AvailableBuildings, AvailableMods, AvailableUnits, IconUrl } from '@/src/core/api'; import { IShortWeapon } from '@/src/types/IUnit'; import { IRaceUnits } from '@/src/types/IUnitShort'; import { IRaceBuildings } from '@/src/types/IBuildingShort'; import '@/src/css/Building.css'; import ArmorType from '@/src/classes/ArmorType'; import WeaponSlot from '@/src/classes/WeaponSlot'; import UnitsTable from '@/src/classes/UnitsTable'; import { IMod } from '@/src/types/Imod'; import { IBuilding } from '@/src/types/IBuilding'; import Vision from '@/src/classes/Vision'; import BuildingAddon from '@/src/classes/building/BuildingAddon'; import { IUnitShort } from '@/src/types/IUnitShort'; import Research, { AffectedResearches } from '@/src/classes/building/Research'; import Required from '@/src/classes/Required'; import { ModifiersProvidesTable } from '@/src/classes/ModifiersProvideTable'; import Ability from '@/src/classes/Ability'; import DeathExplosion from '@/src/classes/DeathExplosion'; import { DescriptionBox } from '@/src/commons/DescriptionBox'; import { BackButton } from '@/src/commons/BackButton'; const SectionTitle = styled(Typography)(({ theme }) => ({ fontWeight: 700, mb: 2, fontSize: '1.25rem', })); const StatsPaper = styled(Paper)(({ theme }) => ({ background: theme.palette.mode === 'dark' ? 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)' : 'linear-gradient(145deg, #ffffff 0%, #f5f5f5 100%)', border: `1px solid ${theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)'}`, borderRadius: '12px', overflow: 'hidden', '& .MuiTableBody .MuiTableRow-root .MuiTableCell-root': { color: theme.palette.text.primary, }, '& .MuiTableBody .MuiTableRow-root .MuiTableCell-head': { color: theme.palette.mode === 'dark' ? '#dee2e6' : 'rgba(0, 0, 0, 0.85)', fontWeight: 600, }, })); const StyledDivider = styled(Divider)(({ theme }) => ({ my: 3, borderColor: theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)', })); const BuildingTitle = styled(Typography)(({ theme }) => ({ fontWeight: 800, mb: 1, display: 'flex', alignItems: 'center', gap: 2, })); const BuildingSubtitle = styled(Typography)(({ theme }) => ({ color: theme.palette.text.secondary, fontWeight: 500, })); const UnitLink = styled(Link)(({ theme }) => ({ color: theme.palette.text.primary, textDecoration: 'none', '&:hover': { color: theme.palette.mode === 'dark' ? '#dee2e6' : 'rgba(0, 0, 0, 0.85)' }, })); const UnitListItem = styled(ListItem)(({ theme }) => ({ color: theme.palette.text.primary, padding: '8px 12px', background: theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.03)' : 'rgba(0,0,0,0.03)', borderRadius: '8px', border: `1px solid ${theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.05)' : 'rgba(0,0,0,0.05)'}`, transition: 'all 0.2s ease', '&:hover': { background: theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.1)' : 'rgba(0,0,0,0.08)', borderColor: theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.3)' : 'rgba(0,0,0,0.2)' }, })); function Unit(unit: IUnitShort, modId: number, raceId: string, theme: Theme) { return ( {unit.icon && } {unit.name} {unit.canDetect &&  } ) } function Building(building: IBuilding, mod: IMod, theme: Theme, racesUnits: IRaceUnits[], racesBuildings: IRaceBuildings[]) { const isDark = theme.palette.mode === 'dark'; let mapBuildingWeapons: Map> = new Map(); building.weapons.forEach(weapon => { const weaponMap = mapBuildingWeapons.get(weapon.hardpoint) if (weaponMap == null) { const weaponMap = new Map() weaponMap.set(weapon.hardpointOrder, weapon.weapon) mapBuildingWeapons.set(weapon.hardpoint, weaponMap) } else { weaponMap.set(weapon.hardpointOrder, weapon.weapon) } }) var buildingName = building.name; if (building.name == null) { buildingName = building.filename.replaceAll('_', ' ').replace('.rgd', ''); } return ( {building.icon && } {buildingName} {mod.name} ({mod.version}) Cost {building.buildCostRequisition > 0 &&    {building.buildCostRequisition.toFixed(0)}} {building.buildCostPower > 0 &&    {building.buildCostPower.toFixed(0)}} {(building.buildCostPopulation !== undefined && building.buildCostPopulation > 0) &&    {building.buildCostPopulation.toFixed(0)}} {(building.buildCostFaith !== undefined && building.buildCostFaith > 0) &&    {building.buildCostFaith}} {(building.buildCostSouls !== undefined && building.buildCostSouls > 0) &&    {building.buildCostSouls.toFixed(0)}} {(building.buildCostTime !== undefined && building.buildCostTime > 0) &&    {building.buildCostTime}s} {(building.requisitionIncome !== undefined && building.requisitionIncome > 0 || building.powerIncome !== undefined && building.powerIncome !== null || building.faithIncome !== undefined && building.faithIncome !== null) && Resource income {building.requisitionIncome !== undefined && building.requisitionIncome != null &&    {building.requisitionIncome}} {building.powerIncome !== undefined && building.powerIncome > 0 &&    {building.powerIncome}} {building.faithIncome !== undefined && building.faithIncome > 0 &&    {building.faithIncome}} } Armor type {building.armorType2 == null ? : } Health   {building.health} {building.healthRegeneration > 0 && +{building.healthRegeneration}/s} Sight Repair max {building.repairMax}
{building.description} {building.requirements !== null && } {building.modifiers.length > 0 && Affected on } {building.units.length > 0 && Unit production {building.units.map(unit => Unit(unit, mod.id, building.race.id, theme) )} } {building.abilities.length > 0 && Abilities {building.abilities.map(a => )} } {building.deathExplosions.length > 0 && {building.deathExplosions.map(da => )} } {building.addons.length > 0 && Addons {building.addons.map(b => )} } {building.researches.length > 0 && Researches {building.researches.map(r => )} } {[...mapBuildingWeapons.keys()].sort(function (a, b) { return a - b; }).map(h => )} Hotkey: {building.hotkey} Filename: {building.filename}
) } export default function BuildingPageClient({ initialBuilding, initialMod, }: { initialBuilding: IBuilding | null; initialMod: IMod | null; }) { const params = useParams() as Record; const { modId, raceId, buildingId } = params; const theme = useTheme(); const [building, setBuilding] = useState(initialBuilding); const [mod, setMod] = useState(initialMod); const [racesUnits, setRacesUnits] = useState([]); const [racesBuildings, setRacesBuildings] = useState([]); useEffect(() => { let cancelled = false; if (building == null) { fetch(AvailableBuildings + "/" + buildingId) .then(res => res.json()) .then((res: IBuilding) => { if (!cancelled) setBuilding(res); }); } if (mod == null) { fetch(AvailableMods + "/" + modId) .then(res => res.json()) .then((res: IMod) => { if (!cancelled) setMod(res); }); } fetch(AvailableUnits + "/mod/" + modId) .then(res => res.json()) .then((resUnits: IRaceUnits[]) => { if (cancelled) return; setRacesUnits(resUnits); if (resUnits.length <= 10) { fetch(AvailableBuildings + "/mod/" + modId) .then(res => res.json()) .then((resBuildings: IRaceBuildings[]) => { if (!cancelled) setRacesBuildings(resBuildings); }); } }); return () => { cancelled = true; }; }, [modId, raceId, buildingId]); if (building != null && mod != null) { const backRef = "/mod/" + modId + "/race/" + raceId; return ( } href={backRef} > Back to race {Building(building, mod, theme, racesUnits, racesBuildings)} ); } else { return ( ); } }