diff --git a/.env b/.env index 98e138b..0a0dc3e 100644 --- a/.env +++ b/.env @@ -1,2 +1,2 @@ -REACT_APP_HOST_URL=http://wiki-backend.dawn-of-war.pro -#REACT_APP_HOST_URL=http://localhost:8082 \ No newline at end of file +#REACT_APP_HOST_URL=http://wiki-backend.dawn-of-war.pro +REACT_APP_HOST_URL=http://localhost:8082 \ No newline at end of file diff --git a/public/images/defence.png b/public/images/defence.png new file mode 100644 index 0000000..2caae5c Binary files /dev/null and b/public/images/defence.png differ diff --git a/src/classes/Sergeant.tsx b/src/classes/Sergeant.tsx index 911bc4a..dc318aa 100644 --- a/src/classes/Sergeant.tsx +++ b/src/classes/Sergeant.tsx @@ -16,6 +16,7 @@ import AvTimerOutlinedIcon from "@mui/icons-material/AvTimer"; import ArmorType from "./ArmorType"; import {ExpandMore} from "@mui/icons-material"; import WeaponSlot from "./WeaponSlot"; +import Vision from "./Vision"; @@ -27,11 +28,6 @@ const Sergeant = (props: SergeantProps) => { const sergeant = props.sergeant - const detect = sergeant.detectRadius > 0 ?   {sergeant.detectRadius} : -   - let mapWithUnitWeapons: Map> = new Map(); sergeant.weapons.forEach(weapon => { @@ -111,7 +107,7 @@ const Sergeant = (props: SergeantProps) => { > detect - {detect} + diff --git a/src/classes/Vision.tsx b/src/classes/Vision.tsx new file mode 100644 index 0000000..e6edf32 --- /dev/null +++ b/src/classes/Vision.tsx @@ -0,0 +1,25 @@ +import React from "react"; +import {Tooltip} from "@mui/material"; + +interface IVision{ + sight: number, + detect: number +} + +function Vision (vision: IVision) { + + return ( +
+ + {vision.sight} + + {vision.detect !== 0 && + {vision.detect} + } +
+ ) +} + +export default Vision; diff --git a/src/classes/WeaponSlot.tsx b/src/classes/WeaponSlot.tsx index 14a3085..37da11d 100644 --- a/src/classes/WeaponSlot.tsx +++ b/src/classes/WeaponSlot.tsx @@ -4,7 +4,8 @@ import {IWeapon} from "../types/IUnit"; export interface WeaponSlotProps { hardpoint: number, - unitWeapons: Map | undefined + unitWeapons: Map | undefined, + showOnlyDefault?: boolean , } const WeaponSlot= (props: WeaponSlotProps) => { @@ -23,6 +24,18 @@ const WeaponSlot= (props: WeaponSlotProps) => { if(onlyDummy) return (
) + if(props.showOnlyDefault){ + + if(firstWeapon.filename.includes("dummy")) return (
); + + return ( +
+

{header}

+
+
+ ) + } + return (

{header}

diff --git a/src/classes/building/BuildingAddon.tsx b/src/classes/building/BuildingAddon.tsx new file mode 100644 index 0000000..938f1e6 --- /dev/null +++ b/src/classes/building/BuildingAddon.tsx @@ -0,0 +1,262 @@ +import React from "react"; +import { + Accordion, + AccordionDetails, + AccordionSummary, + Grid2, + Paper, + Table, + TableBody, + TableCell, + TableContainer, + TableRow +} from "@mui/material"; +import {IAddonModifier, IBuilding, IBuildingAddon, IBuildingAddonShort} 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"; + +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\\garrison_requisition_modifier.lua': + return 'Requisition'; + default: + return mt; + } + } + + 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\\garrison_requisition_modifier.lua': + return ; + default: + return mt; + } + } + + function getChangeDescription(ref: String) { + switch(ref) { + case 'type_modifierusagetype\\tp_mod_usage_addition.lua': + return '+'; + case 'type_modifierusagetype\\tp_mod_usage_multiplication.lua': + return 'x'; + case 'type_modifierusagetype\\tp_mod_usage_percentage.lua': + return '%'; + case 'type_modifierusagetype\\tp_mod_usage_enable.lua': + return ' enable '; + 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[], + weapons: WeaponHardpoint[] +} + +function AddonModifiersProvidesWeapons (props: IAddonModifiersProvidesWeapons) { + + + function getWeaponByAddonMod(ar: IAddonModifier){ + + let hardpoint = Number(ar.reference.replace("modifiers\\default_weapon_modifier_hardpoint", "").replace(".lua", "")); + let value = ar.value; + + //let prevAddonWeaponMod = props.replacedAddonModifiers.find(m => m.reference && m.reference.includes("modifiers\\default_weapon_modifier_hardpoint" + hardpoint))?.value ?? 0 + + let weapon = props.weapons.find(w => w.hardpoint === hardpoint && w.hardpointOrder === 1 + value )?.weapon + if (weapon != null){ + return ; + }else{ + return "Can't find weapon, replaced by addon:" + value + " - " + } + + } + + let weaponMods = props.modifiers.filter(m => m.reference.includes("default_weapon_modifier_hardpoint")) + + return ( +
+ {weaponMods.map(w => getWeaponByAddonMod(w))} +
+ ) +} + + +interface IBuildingAddonProps { + addon: IBuildingAddon, + building: IBuilding +} + +function BuildingAddon(props: IBuildingAddonProps){ + + const addon = props.addon + const building = props.building + + + const prevAddonModifiers: IAddonModifier[] = (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 && ( + + ); + } + + function renderRequirementGlobalAddons(rgas: IBuildingAddonShort[], building: IBuilding) { + return
{rgas.map(rga => +   Global addon: +   + {rga.name} + + )}
+ } + + + return
+ } + aria-controls="panel1-content" + > + + {addon.icon && } +   {addon.name} + + + + + + + + + + Cost + + {addon.addonCostRequisition > 0 && +    + {addon.addonCostRequisition.toFixed(0)}} + {addon.addonCostPower > 0 &&    + {addon.addonCostPower.toFixed(0)}} + {(addon.addonCostPopulation !== undefined && addon.addonCostPopulation > 0) && +    + {addon.addonCostPopulation.toFixed(0)}} + {(addon.addonCostFaith !== undefined && addon.addonCostFaith > 0) && +    + {addon.addonCostFaith}} + {(addon.addonCostSouls !== undefined && addon.addonCostSouls > 0) && +    + {addon.addonCostSouls.toFixed(0)}} + {(addon.addonCostTime !== undefined && addon.addonCostTime > 0) && +    + {addon.addonCostTime}s} + + + + +
+

+ +
+ +
+ {addon.description} +
+
+ {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} +
+
+} + + +export default BuildingAddon; + diff --git a/src/css/Building.css b/src/css/Building.css index 961fb22..050ffc0 100644 --- a/src/css/Building.css +++ b/src/css/Building.css @@ -3,14 +3,8 @@ scroll-margin-top: 15px; } -@-webkit-keyframes blink2 { - 100% { color: rgba(34, 34, 34, 0); } -} -@keyframes blink2 { - 100% { color: rgba(34, 34, 34, 0); } -} -.selected-addon div > h3 { - -webkit-animation: blink2 1s linear infinite; - animation: blink2 1s linear infinite; + +.selected-addon div { + background-color: antiquewhite; } \ No newline at end of file diff --git a/src/pages/BuildingPage.tsx b/src/pages/BuildingPage.tsx index e71eb83..e554716 100644 --- a/src/pages/BuildingPage.tsx +++ b/src/pages/BuildingPage.tsx @@ -1,29 +1,18 @@ -import {AvailableBuildings, AvailableMods, AvailableUnits, IconUrl} from "../core/api"; -import React, {MutableRefObject, useEffect, useRef} from "react"; +import {AvailableBuildings, AvailableMods, IconUrl} from "../core/api"; +import React from "react"; import {withRouter} from "../core/withrouter"; import {IWeapon} from "../types/IUnit"; import '../css/Building.css' -import { - Accordion, - AccordionDetails, - AccordionSummary, - Button, - Grid2, - Paper, - Table, - TableBody, - TableCell, - TableContainer, - TableRow -} from "@mui/material"; -import {ArrowBack, ExpandMore} from "@mui/icons-material"; +import {Button, Grid2, 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'; import WeaponSlot from "../classes/WeaponSlot"; import UnitsTable from "../classes/UnitsTable"; import {IMod} from "../types/Imod"; -import {IBuilding, IBuildingAddon, IBuildingAddonShort} from "../types/IBuilding"; -import {IBuildingShort} from "../types/IBuildingShort"; +import {IBuilding} from "../types/IBuilding"; +import Vision from "../classes/Vision"; +import BuildingAddon from "../classes/building/BuildingAddon"; interface UintPageState { building: IBuilding, @@ -33,10 +22,6 @@ interface UintPageState { function Building(building: IBuilding, mod: IMod) { - const detect = building.detectRadius > 0 ?   {building.detectRadius} : -   let mapBuildingWeapons: Map> = new Map(); @@ -53,117 +38,6 @@ function Building(building: IBuilding, mod: IMod) { - function BuildingAddon(addon: IBuildingAddon){ - - return
- } - aria-controls="panel1-content" - > - - {addon.icon && } -   {addon.name} - - - - - - - - - - Cost - - {addon.addonCostRequisition > 0 && -    - {addon.addonCostRequisition.toFixed(0)}} - {addon.addonCostPower > 0 &&    - {addon.addonCostPower.toFixed(0)}} - {(addon.addonCostPopulation !== undefined && addon.addonCostPopulation > 0) && -    - {addon.addonCostPopulation.toFixed(0)}} - {(addon.addonCostFaith !== undefined && addon.addonCostFaith > 0) && -    - {addon.addonCostFaith}} - {(addon.addonCostSouls !== undefined && addon.addonCostSouls > 0) && -    - {addon.addonCostSouls.toFixed(0)}} - {(addon.addonCostTime !== undefined && addon.addonCostTime > 0) && -    - {addon.addonCostTime}s} - - - - -
-
-
- -
- {addon.description} -
-
- {addon.addonRequirement !== null && - -

Required:

- {addon.addonRequirement.requiredTotalPop !== undefined && addon.addonRequirement.requiredTotalPop !== null && -
  Population:   - {addon.addonRequirement.requiredTotalPop}
- } - {addon.addonRequirement.requireAddon !== null && - - } - {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} -
-
- } - - function renderRequirementBuilding(requirementBuildings: IBuildingShort[], building: IBuilding) { - return requirementBuildings.length > 0 && ( - - ); - } - - function renderRequirementGlobalAddons(rgas: IBuildingAddonShort[], building: IBuilding) { - return
{rgas.map(rga => -   Global addon: -   - {rga.name} - - )}
- } - - return (

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

@@ -227,9 +101,9 @@ function Building(building: IBuilding, mod: IMod) { - Detect + Sight - {detect} + 0 &&

Addons

{building.addons.map(b => - BuildingAddon(b) + )}
} {[...mapBuildingWeapons.keys()].sort(function (a, b) { return a - b; - }).map(h => )} + }).map(h => )} {building.filename} @@ -312,4 +186,6 @@ class BuildingPage extends React.Component { } } -export default withRouter(BuildingPage); \ No newline at end of file +export default withRouter(BuildingPage); + +export { goToAddon }; \ No newline at end of file diff --git a/src/pages/UnitPage.tsx b/src/pages/UnitPage.tsx index e1f9e97..8413f8e 100644 --- a/src/pages/UnitPage.tsx +++ b/src/pages/UnitPage.tsx @@ -23,6 +23,7 @@ import Sergeant from "../classes/Sergeant"; import WeaponSlot from "../classes/WeaponSlot"; import UnitsTable from "../classes/UnitsTable"; import {IMod} from "../types/Imod"; +import Vision from "../classes/Vision"; interface UintPageState { unit: IUnit, @@ -40,11 +41,6 @@ function Unit(unit: IUnit, mod: IMod) { : "-" - const detect = unit.detectRadius > 0 ?   {unit.detectRadius} : -   - let mapWithUnitWeapons: Map> = new Map(); unit.weapons.forEach(weapon => { @@ -214,12 +210,12 @@ function Unit(unit: IUnit, mod: IMod) { - Detect + Vision - {detect} + - {unit.repairMax !== undefined && + {unit.repairMax !== undefined && unit.repairMax !== null && Repair max diff --git a/src/types/IBuilding.tsx b/src/types/IBuilding.tsx index 9e1cf3d..60b75c7 100644 --- a/src/types/IBuilding.tsx +++ b/src/types/IBuilding.tsx @@ -55,6 +55,7 @@ export interface IAddonRequirement { requirementBuildings: IBuildingShort[]; requirementBuildingsEither: IBuildingShort[]; requirementsGlobalAddons: IBuildingAddonShort[]; + replaceWhenDone: Boolean; requireAddon: IBuildingAddonShort; requiredTotalPop?: number; } diff --git a/src/types/IBuildingShort.tsx b/src/types/IBuildingShort.tsx index f783cc0..072837b 100644 --- a/src/types/IBuildingShort.tsx +++ b/src/types/IBuildingShort.tsx @@ -10,5 +10,5 @@ export interface IBuildingShort { icon: string id: number canDetect: boolean - armourTypeName: string + armorTypeName: string }