import Engine, {
AvailableBuilding,
AvailableCommand,
Building,
Command,
Expansion,
Faction,
isShip,
Planet,
Player,
Round,
} from "@gaia-project/engine";
import { qicForDistance } from "@gaia-project/engine/src/cost";
import { isAcademy } from "@gaia-project/engine/src/enums";
import { pick, sortBy } from "lodash";
import { ButtonData } from "../../data";
import { availableBuildingShortcut, buildingName } from "../../data/building";
import { RichText, richText, richTextArrow, richTextBuilding } from "../../graphics/rich-text";
import { hexSelectionButton } from "./hex";
import { withShortcut } from "./shortcuts";
import { CommandController } from "./types";
import { confirmationButton, hexMap, isFree, symbolButton, textButton } from "./utils";
import { commonButtonWarning } from "./warnings";
function buildingMenu(building: Building, faction: Faction): { richText?: RichText; label: string } | null {
if (isShip(building)) {
return { label: "Build Ship" };
}
if (isAcademy(building)) {
return { label: "Upgrade to Academy", richText: [richTextBuilding(Building.Academy1, faction, 1, true)] };
}
return null;
}
function buildingLabel(bld: AvailableBuilding, faction: Faction): { richText: RichText; label: string } {
const building = bld.building;
const name = buildingName(building, faction);
let label = `Build a ${name}`;
const rich = [richTextBuilding(building, faction)];
if (bld.upgrade) {
if (building == Building.Mine) {
label = "Upgrade Gaia Former to Mine";
rich.unshift(richTextBuilding(Building.GaiaFormer, faction), richTextArrow);
} else {
label = withShortcut(`Upgrade to ${name}`, availableBuildingShortcut(bld, faction), ["Upgrade to"]);
}
} else if (bld.downgrade) {
label = `Downgrade to ${name}`;
rich.unshift(richText("Downgrade to"));
} else if (
isFree(bld.cost) ||
building === Building.SpaceStation ||
building === Building.GaiaFormer ||
isShip(building)
) {
label = `Place a ${name}`;
}
return { label, richText: rich };
}
function buildingButton(
controller: CommandController,
building: Building,
label: string,
richText: RichText,
shortcut: string,
command: string,
engine: Engine,
buildings: AvailableBuilding[],
confirm: ButtonData[],
upgrade: boolean,
player: Player
) {
const hexes = hexMap(engine, buildings, false);
if (!upgrade && engine.round != Round.None && building != Building.SpaceStation && !isShip(building)) {
const map = engine.map;
for (const hex of map.grid.values()) {
if (hex.data.planet == Planet.Empty) {
const qicNeeded = qicForDistance(map, hex, player, false, controller.temporaryRange);
if (qicNeeded && qicNeeded.amount <= player.data.qics) {
hexes.hexes.set(hex, { preventClick: true, class: qicNeeded.amount > 0 ? "qic range" : "range" });
}
}
}
}
return hexSelectionButton(
controller,
symbolButton({
label,
richText,
shortcuts: [shortcut],
command,
hexes,
smartAutoClick: !isShip(building),
}),
() => textButton({ buttons: confirm }),
building,
null,
symbolButton
);
}
export function buildButtons(
controller: CommandController,
engine: Engine,
command: AvailableCommand,
player: Player
): ButtonData[] {
const byTypeLabel = new Map();
const faction = engine.player(command.player).faction;
for (const bld of command.data.buildings) {
const key = JSON.stringify(pick(bld, ["building", "upgrade", "downgrade"]));
const old = byTypeLabel.get(key) ?? [];
old.push(bld);
byTypeLabel.set(key, old);
}
const sort = Building.values(Expansion.All);
const sorted = sortBy(
Array.from(byTypeLabel.entries()),
([, b]) => sort.indexOf(b[0].building) * 2 + (b[0].upgrade || b[0].downgrade ? 1 : 0)
);
const ret: ButtonData[] = [];
const menus = new Map();
const menuButtons: ButtonData[] = [];
for (const s of sorted) {
const buildings = s[1] as AvailableBuilding[];
const b = buildings[0];
const label = buildingLabel(b, faction);
const building = b.building;
const shortcut = availableBuildingShortcut(b, faction);
const menu = buildingMenu(building, player.faction);
if (menu) {
const buttons = menus.get(menu.label) ?? [];
if (buttons.length == 0) {
const fac = menu.richText ? symbolButton : textButton;
const menuButton = fac({
label: menu.label,
richText: menu.richText,
command: Command.Build,
buttons,
});
ret.push(menuButton);
menuButtons.push(menuButton);
}
buttons.push(
buildingButton(
controller,
building,
label.label,
label.richText,
shortcut,
building,
engine,
buildings,
[],
b.upgrade,
player
)
);
menus.set(menu.label, buttons);
} else {
ret.push(
buildingButton(
controller,
building,
label.label,
label.richText,
shortcut,
`${Command.Build} ${building}`,
engine,
buildings,
engine.round === Round.None ? confirmationButton(`Confirm ${buildingName(building, faction)}`) : null,
b.upgrade,
player
)
);
}
}
for (const button of menuButtons) {
button.warning = commonButtonWarning(
controller,
"choice",
button.buttons.map((b) => b.warning?.body ?? [])
);
}
return ret;
}