import {
LitElement,
SVGTemplateResult,
TemplateResult,
html,
nothing,
svg,
} from "lit";
import { customElement, property } from "lit/decorators.js";
import {
Difficulty,
Duos,
GameMapType,
GameMode,
HumansVsNations,
Quads,
Trios,
UnitType,
} from "../../core/game/Game";
import { TeamCountConfig } from "../../core/Schemas";
import { translateText } from "../Utils";
import "./Difficulties";
import "./FluentSlider";
import "./map/MapPicker";
const ACTIVE_CARD =
"bg-blue-500/20 border-blue-500/50 shadow-[0_0_15px_rgba(59,130,246,0.2)]";
const INACTIVE_CARD =
"bg-white/5 border-white/10 hover:bg-white/10 hover:border-white/20";
const DISABLED_CARD =
"w-full rounded-xl border transition-all duration-200 opacity-30 grayscale cursor-not-allowed bg-white/5 border-white/5";
function cardClass(active: boolean, extra = ""): string {
return `w-full rounded-xl border cursor-pointer transition-all duration-200 active:scale-95 ${extra} ${active ? ACTIVE_CARD : INACTIVE_CARD}`;
}
const CARD_LABEL_CLASS =
"text-xs uppercase font-bold tracking-wider leading-tight break-words hyphens-auto";
const DIFFICULTY_OPTIONS = Object.entries(Difficulty).filter(([key]) =>
isNaN(Number(key)),
) as Array<[string, Difficulty]>;
const TEAM_COUNT_OPTIONS: TeamCountConfig[] = [
2,
3,
4,
5,
6,
7,
Quads,
Trios,
Duos,
HumansVsNations,
];
function stateTextClass(active: boolean): string {
return active ? "text-white" : "text-white/60";
}
function renderTextCardButton(
label: string,
active: boolean,
onClick: () => void,
cardExtraClass: string,
): TemplateResult {
return html`
`;
}
function renderSection(
iconSvg: SVGTemplateResult,
colorClass: string,
bgClass: string,
titleKey: string,
content: TemplateResult | TemplateResult[],
sectionClass = "space-y-6",
): TemplateResult {
return html`
${renderSectionHeader(iconSvg, colorClass, bgClass, titleKey)} ${content}
`;
}
const unitOptions: { type: UnitType; translationKey: string }[] = [
{ type: UnitType.City, translationKey: "unit_type.city" },
{ type: UnitType.DefensePost, translationKey: "unit_type.defense_post" },
{ type: UnitType.Port, translationKey: "unit_type.port" },
{ type: UnitType.Warship, translationKey: "unit_type.warship" },
{ type: UnitType.TransportShip, translationKey: "unit_type.boat" },
{ type: UnitType.MissileSilo, translationKey: "unit_type.missile_silo" },
{ type: UnitType.SAMLauncher, translationKey: "unit_type.sam_launcher" },
{ type: UnitType.AtomBomb, translationKey: "unit_type.atom_bomb" },
{ type: UnitType.HydrogenBomb, translationKey: "unit_type.hydrogen_bomb" },
{ type: UnitType.MIRV, translationKey: "unit_type.mirv" },
{ type: UnitType.Factory, translationKey: "unit_type.factory" },
];
const MAP_ICON = svg``;
const DIFFICULTY_ICON = svg``;
const MODE_ICON = svg``;
const OPTIONS_ICON = svg``;
const ENABLES_ICON = svg``;
function renderSectionHeader(
iconSvg: SVGTemplateResult,
colorClass: string,
bgClass: string,
titleKey: string,
): TemplateResult {
return html`
${translateText(titleKey)}
`;
}
export interface ToggleOptionConfig {
labelKey: string;
checked: boolean;
hidden?: boolean;
}
export interface GameConfigSettingsData {
map: {
selected: GameMapType;
useRandom: boolean;
randomMapDivider?: boolean;
showMedals?: boolean;
mapWins?: Map>;
};
difficulty: {
selected: Difficulty;
disabled: boolean;
};
gameMode: {
selected: GameMode;
};
teamCount: {
selected: TeamCountConfig;
};
options: {
titleKey: string;
bots: {
value: number;
labelKey: string;
disabledKey: string;
};
nations?: {
value: number;
defaultValue?: number;
labelKey: string;
disabledKey: string;
hidden?: boolean;
};
toggles: ToggleOptionConfig[];
inputCards: TemplateResult[];
};
unitTypes: {
titleKey: string;
disabledUnits: UnitType[];
};
}
@customElement("game-config-settings")
export class GameConfigSettings extends LitElement {
@property({ attribute: false }) settings?: GameConfigSettingsData;
@property({ attribute: false }) sectionGapClass = "space-y-6";
createRenderRoot() {
return this;
}
private emit(name: string, detail: T) {
this.dispatchEvent(
new CustomEvent(name, {
detail,
bubbles: true,
composed: true,
}),
);
}
private handleSelectMap = (map: GameMapType) => {
this.emit("map-selected", { map });
};
private handleSelectRandom = () => {
this.emit("random-map-selected", {});
};
private handleDifficultySelect = (difficulty: Difficulty) => {
this.emit("difficulty-selected", { difficulty });
};
private handleGameModeSelect = (mode: GameMode) => {
this.emit("game-mode-selected", { mode });
};
private handleTeamCountSelect = (count: TeamCountConfig) => {
this.emit("team-count-selected", { count });
};
private handleOptionToggle = (toggle: ToggleOptionConfig) => {
this.emit("option-toggle-changed", {
labelKey: toggle.labelKey,
checked: !toggle.checked,
});
};
private handleBotsChanged = (event: Event) => {
const customEvent = event as CustomEvent<{ value: number }>;
this.emit("bots-changed", customEvent.detail);
};
private handleNationsChanged = (event: Event) => {
const customEvent = event as CustomEvent<{ value: number }>;
this.emit("nations-changed", customEvent.detail);
};
private handleUnitToggle = (unit: UnitType, checked: boolean) => {
this.emit("unit-toggle-changed", { unit, checked });
};
private renderOptionToggle(toggle: ToggleOptionConfig): TemplateResult {
if (toggle.hidden) return html``;
return renderTextCardButton(
translateText(toggle.labelKey),
toggle.checked,
() => this.handleOptionToggle(toggle),
"p-4 text-center",
);
}
private renderUnitTypeOptions(disabledUnits: UnitType[]): TemplateResult[] {
return unitOptions.map(({ type, translationKey }) => {
const isEnabled = !disabledUnits.includes(type);
return html`
`;
});
}
render() {
if (!this.settings) return nothing;
const settings = this.settings;
return html`
${renderSection(
MAP_ICON,
"text-blue-400",
"bg-blue-500/20",
"map.map",
html`
`,
)}
${renderSection(
DIFFICULTY_ICON,
"text-green-400",
"bg-green-500/20",
"difficulty.difficulty",
html`
${DIFFICULTY_OPTIONS.map(([key, value]) => {
const isSelected = settings.difficulty.selected === value;
const isDisabled = settings.difficulty.disabled;
return html`
`;
})}
`,
)}
${renderSection(
MODE_ICON,
"text-purple-400",
"bg-purple-500/20",
"host_modal.mode",
html`
${[GameMode.FFA, GameMode.Team].map((mode) => {
const isSelected = settings.gameMode.selected === mode;
return html`
`;
})}
`,
)}
${settings.gameMode.selected === GameMode.FFA
? nothing
: html`
${translateText("host_modal.team_count")}
${TEAM_COUNT_OPTIONS.map((o) => {
const isSelected = settings.teamCount.selected === o;
return html`
`;
})}
`}
${renderSection(
OPTIONS_ICON,
"text-orange-400",
"bg-orange-500/20",
settings.options.titleKey,
html`
${settings.options.nations && !settings.options.nations.hidden
? html`
`
: nothing}
${settings.options.toggles.map((toggle) =>
this.renderOptionToggle(toggle),
)}
${settings.options.inputCards}
`,
)}
${renderSection(
ENABLES_ICON,
"text-teal-400",
"bg-teal-500/20",
settings.unitTypes.titleKey,
html`
${this.renderUnitTypeOptions(settings.unitTypes.disabledUnits)}
`,
"space-y-6 pb-6",
)}
`;
}
}