diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index 03d9549..c1d0389 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -2,5 +2,6 @@ \ No newline at end of file diff --git a/src/classes/ArmorType.tsx b/src/classes/ArmorType.tsx index 679e389..19aa082 100644 --- a/src/classes/ArmorType.tsx +++ b/src/classes/ArmorType.tsx @@ -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 { public static defaultProps = { - withName: false + compact: true }; renderArmorImage(armorTypeId: string): string { @@ -20,11 +21,11 @@ class ArmorType extends React.Component { 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 { 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 { } render() { + if(this.props.compact){ + return ( {this.props.compact ? +
{this.props.name} +
: + {this.props.name}}
); + } else + return {this.props.name} ; - return ( {this.props.withName && this.props.name}); } } diff --git a/src/classes/LobbyList.js b/src/classes/LobbyList.js deleted file mode 100644 index 65dd4fe..0000000 --- a/src/classes/LobbyList.js +++ /dev/null @@ -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
    { this.state.messages.slice(-5).map( (msg, idx) =>
  • { msg }
  • )}
; - } -}; \ No newline at end of file diff --git a/src/classes/ModifiersProvideTable.tsx b/src/classes/ModifiersProvideTable.tsx new file mode 100644 index 0000000..0415a04 --- /dev/null +++ b/src/classes/ModifiersProvideTable.tsx @@ -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 Next icon cost ; + case 'modifiers\\holy_icon_cost_requisition.lua': + return Next icon cost ; + 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 ; + case 'modifiers\\health_maximum_modifier.lua': + return ; + case 'modifiers\\keen_sight_radius_modifier.lua': + return ; + case 'modifiers\\sight_radius_modifier.lua': + return ; + case 'modifiers\\faith_max_modifier.lua': + return ; + case 'modifiers\\garrison_requisition_modifier.lua': + return ; + case 'modifiers\\cost_requisition_modifier.lua': + return ; + case 'modifiers\\morale_maximum_squad_modifier.lua': + return ; + 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 ( + + + {noWeaponMods.map(m => + + {getModName(m.reference)} + {getModIcon(m.reference)} {getChangeDescription(m.usageType, m.value)} + + )} +
+
+ ) +} + +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 + {affectedUnit.name} + + } + var affectedSergeant = research.affectedSergeants.find(as => as.filename.replaceAll('.rgd', '') === target); + if(affectedSergeant != null) { + return {affectedSergeant.name} at + {affectedSergeant.unit.name} + + } + var affectedBuilding = research.affectedBuildings.find(ab => ab.filename.replaceAll('.rgd', '') === target); + if(affectedBuilding != null) { + return + {affectedBuilding.name} + + } + + var affectedWeapon = research.affectedWeapons.find(aw => aw.filename.replaceAll('.rgd', '') === target); + if (affectedWeapon != null) { + return {affectedWeapon.name ? affectedWeapon.name : affectedWeapon.filename.replaceAll('_', ' ').replace('.rgd', '')} at { + affectedWeapon.units.map(unit => + + {unit.name} + + ) + } + { + affectedWeapon.sergeants.map(affectedSergeant => + {affectedSergeant.name} at + {affectedSergeant.unit.name} + + ) + } + { + affectedWeapon.buildings.map(affectedBuilding => + + {affectedBuilding.name} + + ) + } + + } + + + return Unknown target {target}; + } + + return ( + + + {mods.map(m => + + {getTarget(m.target, props.research, props.race)} + {getModName(m.reference)} + {getModIcon(m.reference)} {getChangeDescription(m.usageType, m.value)} + + )} +
+
+ ) +} + +export function getIcon(icon?: string): string{ + if(icon !== null && icon !== undefined){ + return IconUrl + icon.replaceAll('\\', '/') + } else return '/images/shakal.png' +} + + diff --git a/src/classes/Required.tsx b/src/classes/Required.tsx new file mode 100644 index 0000000..40f6371 --- /dev/null +++ b/src/classes/Required.tsx @@ -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
{rgas.map(rga => + +   Global addon: +   + {rga.name} + + )}
+ } + + function renderRequirementBuilding(requirementBuildings: IBuildingShort[], building: IBuilding, modId: number) { + return requirementBuildings.length > 0 && ( +
  Buildings: +  {" "} + {requirementBuildings[0].name} + {requirementBuildings[1] !== undefined && or   +  {" "} + {requirementBuildings[1].name} }
+ ); + } + + function renderRequirementResearches(requirementResearches: IResearchRequirements[], modId: number, raceId: string) { + return
{requirementResearches.map(rs => + +   Research {rs.researchMustNotBeComplete ? "not" : ""}: +   + {rs.researchShortDto.name} + + )}
+ } + + const requirement = props.requirement + const building = props.building + + + return ( +
+

Required:

+ {requirement.requiredTotalPop !== undefined && requirement.requiredTotalPop !== null && +
  Population:   + {requirement.requiredTotalPop}
+ } + {requirement.requireAddon !== null && +
  Addon:   + goToAddon(`#addon-` + requirement.requireAddon.id)}>{requirement.requireAddon.name} + {requirement.replaceWhenDone && (old provides replace)} +
+ } + {requirement.requirementBuildings.map(b => +
  Building:   + {b.name}
) + } + {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)} +
+ ) +} + +export function getIcon(icon?: string): string{ + if(icon !== null && icon !== undefined){ + return IconUrl + icon.replaceAll('\\', '/') + } else return '/images/shakal.png' +} + + + + +export default Required; diff --git a/src/classes/Sergeant.tsx b/src/classes/Sergeant.tsx index 059c272..8c0960b 100644 --- a/src/classes/Sergeant.tsx +++ b/src/classes/Sergeant.tsx @@ -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) => { > Armor type - + + {sergeant.armorType2 &&
after upgrade can become:
}
{ - Detect + Vision @@ -144,7 +149,10 @@ const Sergeant = (props: SergeantProps) => { {[...mapWithUnitWeapons.keys()].sort(function (a, b) { return a - b; - }).map(h => )} + }).map(h => )} + + + {renderAffectedResearches(sergeant.affectedResearches, props.mod.id, props.race.id)} {sergeant.filename} diff --git a/src/classes/TimerExample.js b/src/classes/TimerExample.js deleted file mode 100644 index bd7edf6..0000000 --- a/src/classes/TimerExample.js +++ /dev/null @@ -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); - - // Хоть мы и возвращаем целый

элемент, react разумно обновит - // только измененные части, содержащие переменную seconds. - - return

This example was started {seconds} seconds ago.

; - } -}; \ No newline at end of file diff --git a/src/classes/Weapon.tsx b/src/classes/Weapon.tsx index de89ce9..1e862ff 100644 --- a/src/classes/Weapon.tsx +++ b/src/classes/Weapon.tsx @@ -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 { 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 { 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 { { this.props.mod !== undefined && this.props.mod.name.includes("Ultimate Apocalypse") ? - +
{ + src="/images/ARM_Morale.webp"/> +
+ Morale
+
@@ -386,7 +395,10 @@ class Weapon extends React.Component { + src="/images/ARM_Morale.webp"/> +
+ Morale
+ @@ -415,6 +427,9 @@ class Weapon extends React.Component { {weapon.filename} + + {renderAffectedResearches(weapon.affectedResearches, this.props.mod.id, this.props.race.id)} + diff --git a/src/classes/WeaponSlot.tsx b/src/classes/WeaponSlot.tsx index 0ea2258..30cd406 100644 --- a/src/classes/WeaponSlot.tsx +++ b/src/classes/WeaponSlot.tsx @@ -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 | undefined, mod: IMod, + race: Irace, showOnlyDefault?: boolean , } @@ -33,7 +35,7 @@ const WeaponSlot= (props: WeaponSlotProps) => { return (

{header}

-
+
) } @@ -43,7 +45,7 @@ const WeaponSlot= (props: WeaponSlotProps) => {

{header}

{weaponsSorted.filter(wp => !wp[1].filename.includes("dummy")).map(wp => -
+
)} ) diff --git a/src/classes/building/BuildingAddon.tsx b/src/classes/building/BuildingAddon.tsx index b2eb7cb..a2c918b 100644 --- a/src/classes/building/BuildingAddon.tsx +++ b/src/classes/building/BuildingAddon.tsx @@ -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 Next icon cost ; - case 'modifiers\\holy_icon_cost_requisition.lua': - return Next icon cost ; - 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 ; - case 'modifiers\\health_maximum_modifier.lua': - return ; - case 'modifiers\\keen_sight_radius_modifier.lua': - return ; - case 'modifiers\\sight_radius_modifier.lua': - return ; - case 'modifiers\\faith_max_modifier.lua': - return ; - case 'modifiers\\garrison_requisition_modifier.lua': - return ; - case 'modifiers\\cost_requisition_modifier.lua': - return ; - 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 ( - -
- {noWeaponMods.map(m => - - {getModName(m.reference)} - {getModIcon(m.reference)} {getChangeDescription(m.usageType, m.value)} - - )} -
-
- ) -} 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 ; + return ; }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 && ( -
  Buildings: -  {" "} - {requirementBuildings[0].name} - {requirementBuildings[1] !== undefined && or   -  {" "} - {requirementBuildings[1].name} }
- ); - } - function renderRequirementGlobalAddons(rgas: IBuildingAddonShort[], building: IBuilding) { - return
{rgas.map(rga => -   Global addon: -   - {rga.name} - - )}
- } - - - return
+ return
} aria-controls="panel1-content" > - {addon.icon && } +   {addon.name} @@ -242,7 +129,7 @@ function BuildingAddon(props: IBuildingAddonProps){
- +
@@ -251,32 +138,11 @@ function BuildingAddon(props: IBuildingAddonProps){ {addon.addonModifiers !== null && - + } {addon.addonRequirement !== null && -

Required:

- {addon.addonRequirement.requiredTotalPop !== undefined && addon.addonRequirement.requiredTotalPop !== null && -
  Population:   - {addon.addonRequirement.requiredTotalPop}
- } - {addon.addonRequirement.requireAddon !== null && -
  Addon:   - goToAddon(`#addon-` + addon.addonRequirement.requireAddon.id)}>{addon.addonRequirement.requireAddon.name} - {addon.addonRequirement.replaceWhenDone && (old provides replace)} -
- } - {addon.addonRequirement.requirementBuildings.map(b => -
  Building:   - {b.name}
) - } - {addon.addonRequirement.requirementBuildingsEither.length !== 0 && - renderRequirementBuilding(addon.addonRequirement.requirementBuildingsEither, building)} - {addon.addonRequirement.requirementsGlobalAddons.length !== 0 && - renderRequirementGlobalAddons(addon.addonRequirement.requirementsGlobalAddons, building)} +
} {addon.filename} diff --git a/src/classes/building/Research.tsx b/src/classes/building/Research.tsx new file mode 100644 index 0000000..981e490 --- /dev/null +++ b/src/classes/building/Research.tsx @@ -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
+ } + aria-controls="panel1-content" + > + + +   {research.name} + + + + + + + + + + Cost + + {research.costRequisition > 0 && +    + {research.costRequisition.toFixed(0)}} + {research.costPower > 0 &&    + {research.costPower.toFixed(0)}} + {(research.costPopulation !== undefined && research.costPopulation > 0) && +    + {research.costPopulation.toFixed(0)}} + {(research.costFaith !== undefined && research.costFaith > 0) && +    + {research.costFaith}} + {(research.costSouls !== undefined && research.costSouls > 0) && +    + {research.costSouls.toFixed(0)}} + {(research.costTime !== undefined && research.costTime > 0) && +    + {research.costTime}s} + + + + +
+

+
+ +
+ {research.description} +
+ +
+ + + + {research.requirements !== null && + + + } +
+ {research.filename} +
+
+ +} + +export function renderAffectedResearches(researches: IResearchShort[], modId: number, raceId: string) { + + function researchLink(rs: IResearchShort) { + return +   + {rs.name} + + } + + return
{researches.map(rs => + rs.buildingId == null ? : + Research affect: {researchLink(rs)}
+ )}
+} + + +export default ResearchFull; + diff --git a/src/css/Building.css b/src/css/Building.css index 050ffc0..9a2a40a 100644 --- a/src/css/Building.css +++ b/src/css/Building.css @@ -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; } \ No newline at end of file diff --git a/src/pages/BuildingPage.tsx b/src/pages/BuildingPage.tsx index 533d9f9..aca4c4e 100644 --- a/src/pages/BuildingPage.tsx +++ b/src/pages/BuildingPage.tsx @@ -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 ( + {unit.icon && } + {unit.name} + {unit.canDetect &&  } + + ) +} + 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 (

{mod.name} ({mod.version})

{building.icon && - } {building.name}

+ } {buildingName} @@ -103,7 +130,8 @@ function Building(building: IBuilding, mod: IMod) { > Armor type - + + {building.armorType2 &&
}
+ {building.units.length > 0 && +

Unit production

+ {building.units.map(unit => + Unit(unit, mod.id, building.race.id) + )} +
} {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 => )} + }).map(h => )} + + + {renderAffectedResearches(building.affectedResearches, mod.id, building.race.id)}
{building.filename} @@ -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 { @@ -188,6 +239,7 @@ class BuildingPage extends React.Component { mod: modData }); goToAddon(window.location.hash); + goToResearch(window.location.hash); } render() { @@ -207,4 +259,4 @@ class BuildingPage extends React.Component { export default withRouter(BuildingPage); -export { goToAddon }; \ No newline at end of file +export { goToAddon, goToResearch }; \ No newline at end of file diff --git a/src/pages/ModsPage.tsx b/src/pages/ModsPage.tsx index 5f72d26..b1796fd 100644 --- a/src/pages/ModsPage.tsx +++ b/src/pages/ModsPage.tsx @@ -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(

{modName}

@@ -28,9 +30,9 @@ function Mods (mods: IMod[]) { {sameMods.filter((m) => !m.isBeta).map(mod =>
    {mod.version}
)} {sameMods.find((m) => m.isBeta) != null &&
Beta versions:
} - {sameMods.find((m) => m.isBeta) != null && - sameMods.filter((m) => m.isBeta).map(mod => -
    {mod.version}
)} + {lastBeta != null && +
    {lastBeta.version}
+ }
) } diff --git a/src/pages/RacePageFast.tsx b/src/pages/RacePageFast.tsx index 19fb2e5..0741e4a 100644 --- a/src/pages/RacePageFast.tsx +++ b/src/pages/RacePageFast.tsx @@ -62,7 +62,7 @@ function UnitSmall (unit: IUnitShort, modId: number, raceId: String) { return ( {unit.icon && } {unitName} - {unit.canDetect &&   }
) } @@ -140,21 +140,23 @@ class Units extends React.Component {

All units

- -

Infantry

- {this.state.units.infantry.map(unit => Unit(unit, this.props.modId, this.props.raceId))} -
- -

Tech

- - {this.state.units.tech.map(unit => Unit(unit, this.props.modId, this.props.raceId))} - -
- -

Support

- - {this.state.units.support.map(unit => Unit(unit, this.props.modId, this.props.raceId))} - + + +

Infantry

+ {this.state.units.infantry.map(unit => Unit(unit, this.props.modId, this.props.raceId))} +
+ +

Tech

+ + {this.state.units.tech.map(unit => Unit(unit, this.props.modId, this.props.raceId))} + +
+ +

Support

+ + {this.state.units.support.map(unit => Unit(unit, this.props.modId, this.props.raceId))} + +
diff --git a/src/pages/UnitPage.tsx b/src/pages/UnitPage.tsx index a845c7c..71d386f 100644 --- a/src/pages/UnitPage.tsx +++ b/src/pages/UnitPage.tsx @@ -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) { > Armor type - + + {unit.armorType2 &&
after upgrade can become:
}
  {unit.health} {unit.healthRegeneration > 0 && +{unit.healthRegeneration}/s} - {unit.armour !== undefined && unit.armour > 0 && {unit.armour} } + {unit.armour !== undefined && unit.armour !== 0 && {unit.armour} } } - {unit.repairSpeed !== undefined && unit.repairSpeed !== null && + {unit.repairSpeed !== undefined && unit.repairSpeed !== null && unit.repairCostPercent !== null && - Repair speed + Repair - {unit.repairSpeed} + {unit.repairSpeed} hp/s; {unit.repairCostPercent}% cost } @@ -271,7 +277,7 @@ function Unit(unit: IUnit, mod: IMod) { 0}/> - +
@@ -280,7 +286,10 @@ function Unit(unit: IUnit, mod: IMod) { {[...mapWithUnitWeapons.keys()].sort(function (a, b) { return a - b; - }).map(h => )} + }).map(h => )} + + + {renderAffectedResearches(unit.affectedResearches, mod.id, unit.race.id)} {unit.filename} @@ -290,6 +299,8 @@ function Unit(unit: IUnit, mod: IMod) { } + + class UnitPage extends React.Component { diff --git a/src/types/ArmorTypeValues.ts b/src/types/ArmorTypeValues.ts index 804ee75..70ebdb9 100644 --- a/src/types/ArmorTypeValues.ts +++ b/src/types/ArmorTypeValues.ts @@ -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', diff --git a/src/types/IAffectedEntity.tsx b/src/types/IAffectedEntity.tsx new file mode 100644 index 0000000..af88bdc --- /dev/null +++ b/src/types/IAffectedEntity.tsx @@ -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[] +} \ No newline at end of file diff --git a/src/types/IBuilding.tsx b/src/types/IBuilding.tsx index c31f930..c9d200e 100644 --- a/src/types/IBuilding.tsx +++ b/src/types/IBuilding.tsx @@ -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; -} \ No newline at end of file diff --git a/src/types/IModifier.tsx b/src/types/IModifier.tsx new file mode 100644 index 0000000..7104072 --- /dev/null +++ b/src/types/IModifier.tsx @@ -0,0 +1,8 @@ + +export interface IModifier { + id: number; + reference: string; + usageType: string; + target: string; + value: number; +} \ No newline at end of file diff --git a/src/types/IRequirement.tsx b/src/types/IRequirement.tsx new file mode 100644 index 0000000..7b6a751 --- /dev/null +++ b/src/types/IRequirement.tsx @@ -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; +} \ No newline at end of file diff --git a/src/types/IResearch.tsx b/src/types/IResearch.tsx new file mode 100644 index 0000000..6c4be33 --- /dev/null +++ b/src/types/IResearch.tsx @@ -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[] +} \ No newline at end of file diff --git a/src/types/IResearchRequirements.tsx b/src/types/IResearchRequirements.tsx new file mode 100644 index 0000000..4b9172b --- /dev/null +++ b/src/types/IResearchRequirements.tsx @@ -0,0 +1,6 @@ +import {IResearchShort} from "./IResearchShort"; + +export interface IResearchRequirements { + researchShortDto: IResearchShort, + researchMustNotBeComplete: Boolean, +} \ No newline at end of file diff --git a/src/types/IResearchShort.tsx b/src/types/IResearchShort.tsx new file mode 100644 index 0000000..e4833b3 --- /dev/null +++ b/src/types/IResearchShort.tsx @@ -0,0 +1,6 @@ +export interface IResearchShort { + id: string; + name: string; + icon: string; + buildingId: number; +} \ No newline at end of file diff --git a/src/types/IUnit.tsx b/src/types/IUnit.tsx index 2ee8326..213d792 100644 --- a/src/types/IUnit.tsx +++ b/src/types/IUnit.tsx @@ -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 {