'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 (
);
}
}