Add research support

This commit is contained in:
Anibus
2025-08-18 13:02:10 +03:00
parent f94553bb9a
commit 851bb71601
25 changed files with 714 additions and 311 deletions
+16 -150
View File
@@ -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 <span>Next icon cost <img style={{verticalAlign: "top"}} src='/images/Resource_power.gif'/></span>;
case 'modifiers\\holy_icon_cost_requisition.lua':
return <span>Next icon cost <img style={{verticalAlign: "top"}} src='/images/Resource_requisition.gif'/></span>;
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 <img style={{height: 20, verticalAlign: "top"}} src='/images/defence.png'/>;
case 'modifiers\\health_maximum_modifier.lua':
return <img style={{verticalAlign: "top"}} src='/images/Health_icon.webp'/>;
case 'modifiers\\keen_sight_radius_modifier.lua':
return <img style={{verticalAlign: "top"}} src='/images/DETECT_YES.webp'/>;
case 'modifiers\\sight_radius_modifier.lua':
return <img style={{verticalAlign: "top"}} src='/images/DETECT_NO.webp'/>;
case 'modifiers\\faith_max_modifier.lua':
return <img style={{verticalAlign: "top"}} src='/images/Resource_faith.gif'/>;
case 'modifiers\\garrison_requisition_modifier.lua':
return <img style={{verticalAlign: "top"}} src='/images/Resource_requisition.gif'/>;
case 'modifiers\\cost_requisition_modifier.lua':
return <img style={{verticalAlign: "top"}} src='/images/Resource_requisition.gif'/>;
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 (
<TableContainer component={Paper}>
<Table size="small" aria-label="a dense table">
{noWeaponMods.map(m =>
<TableRow
sx={{'&:last-child td, &:last-child th': {border: 0}}}
>
<TableCell component="th" scope="row">{getModName(m.reference)}</TableCell>
<TableCell component="th" scope="row">{getModIcon(m.reference)} {getChangeDescription(m.usageType, m.value)}</TableCell>
</TableRow>
)}
</Table>
</TableContainer>
)
}
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 <WeaponSlot mod={props.mod} unitWeapons={new Map().set(hardpoint, weapon)} hardpoint={hardpoint}/>;
return <WeaponSlot race={props.race} mod={props.mod} unitWeapons={new Map().set(hardpoint, weapon)} hardpoint={hardpoint}/>;
}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 && (
<div>&nbsp; Buildings: <img style={{verticalAlign: "top", height: 25}}
src={IconUrl + requirementBuildings[0].icon.replaceAll('\\', '/')}/>
&nbsp;{" "}<a href={`/mod/${props.mod.id}/race/${building.race.id}/building/${requirementBuildings[0].id}`}>
{requirementBuildings[0].name}
</a> {requirementBuildings[1] !== undefined && <span>or &nbsp;<img style={{verticalAlign: "top", height: 25}}
src={IconUrl + requirementBuildings[1].icon.replaceAll('\\', '/')}/>
&nbsp;{" "}<a href={`/mod/${props.mod.id}/race/${building.race.id}/building/${requirementBuildings[1].id}`}>
{requirementBuildings[1].name}</a></span> } </div>
);
}
function renderRequirementGlobalAddons(rgas: IBuildingAddonShort[], building: IBuilding) {
return <div> {rgas.map(rga =>
<span>&nbsp; Global addon: <img style={{verticalAlign: "top", height: 25}}
src={IconUrl + rga.icon.replaceAll('\\', '/')}/>
&nbsp;<a href={`/mod/${props.mod.id}/race/${building.race.id}/building/${rga.buildingId}#addon-${rga.id}`}>
{rga.name}
</a></span>
)}</div>
}
return <div className='addon-accordion' id={"addon-" + addon.id} ><Accordion>
return <div className='addon-research-accordion' id={"addon-" + addon.id} ><Accordion>
<AccordionSummary
expandIcon={<ExpandMore/>}
aria-controls="panel1-content"
>
<span style={{fontSize: 20}}>
{addon.icon && <img className="sergeantIcon" src={IconUrl + addon.icon.replaceAll('\\', '/')}/>}
<img className="sergeantIcon" src={getIcon(addon.icon)}/>
&nbsp; {addon.name}
</span>
</AccordionSummary>
@@ -242,7 +129,7 @@ function BuildingAddon(props: IBuildingAddonProps){
</TableBody>
</Table>
</TableContainer><br/>
<AddonModifiersProvidesTable modifiers={addon.addonModifiers}/>
<ModifiersProvidesAddonTable modifiers={addon.addonModifiers}/>
</Grid2>
<Grid2 size={{xs: 12, md: 8}}>
<div style={{whiteSpace: "pre-wrap"}}>
@@ -251,32 +138,11 @@ function BuildingAddon(props: IBuildingAddonProps){
</Grid2>
{addon.addonModifiers !== null &&
<Grid2 size={{xs: 12, md: 12}}>
<AddonModifiersProvidesWeapons mod={props.mod} modifiers={addon.addonModifiers} replacedAddonModifiers={prevAddonModifiers} weapons={building.weapons}/>
<AddonModifiersProvidesWeapons race={building.race} mod={props.mod} modifiers={addon.addonModifiers} replacedAddonModifiers={prevAddonModifiers} weapons={building.weapons}/>
</Grid2>}
{addon.addonRequirement !== null &&
<Grid2 size={{xs: 12, md: 12}}>
<h4>Required: </h4>
{addon.addonRequirement.requiredTotalPop !== undefined && addon.addonRequirement.requiredTotalPop !== null &&
<div>&nbsp; Population: <img style={{verticalAlign: "top", height: 25}}
src="/images/Resource_orksquadcap.gif"/>&nbsp;
{addon.addonRequirement.requiredTotalPop}</div>
}
{addon.addonRequirement.requireAddon !== null &&
<div>&nbsp; Addon: <img style={{verticalAlign: "top", height: 25}}
src={IconUrl + addon.addonRequirement.requireAddon.icon.replaceAll('\\', '/')}/>&nbsp;
<a href={"#addon-" + addon.addonRequirement.requireAddon.id} onClick={() => goToAddon(`#addon-` + addon.addonRequirement.requireAddon.id)}>{addon.addonRequirement.requireAddon.name}</a>
{addon.addonRequirement.replaceWhenDone && <i> (old provides replace)</i>}
</div>
}
{addon.addonRequirement.requirementBuildings.map(b =>
<div>&nbsp; Building: <img style={{verticalAlign: "top", height: 25}}
src={IconUrl + b.icon.replaceAll('\\', '/')}/>&nbsp;
<a href= {'/mod/'+ props.mod.id +'/race/'+ building.race.id +'/building/' + b.id + "/"}>{b.name}</a></div>)
}
{addon.addonRequirement.requirementBuildingsEither.length !== 0 &&
renderRequirementBuilding(addon.addonRequirement.requirementBuildingsEither, building)}
{addon.addonRequirement.requirementsGlobalAddons.length !== 0 &&
renderRequirementGlobalAddons(addon.addonRequirement.requirementsGlobalAddons, building)}
<Required requirement={addon.addonRequirement} building={building}/>
</Grid2>}
</Grid2>
<i className="rgdFrom">{addon.filename}</i>