UI Components¶
Add custom buttons and interfaces to the game.
Overview¶
The SDK provides ModActionButton for adding custom buttons to the game's attack menu:
import { ModActionButton, ModButtonContext } from '@lands.io/mod-sdk';
class DonateButton extends ModActionButton {
get icon() {
return 'donate-icon.png';
}
get label() {
return 'Donate';
}
get intentName() {
return 'donate';
}
shouldShow(context: ModButtonContext): boolean {
return context.myPlayer !== null;
}
}
ModActionButton¶
Required Properties¶
abstract get icon(): string; // Icon path/URL
abstract get label(): string; // Button label
abstract get intentName(): string; // Intent name for handler
Required Methods¶
Optional Methods¶
// Payload to send with the intent
getPayload(context: ModButtonContext): unknown {
return {};
}
// Is the button disabled (visible but not clickable)?
isDisabled(context: ModButtonContext): boolean {
return false;
}
Styling Properties¶
get cost(): number | undefined { return undefined; }
get fillColor(): string | undefined { return undefined; }
get strokeColor(): string | undefined { return undefined; }
get hoverFillColor(): string | undefined { return undefined; }
get hoverStrokeColor(): string | undefined { return undefined; }
get disabledFillColor(): string | undefined { return undefined; }
get disabledStrokeColor(): string | undefined { return undefined; }
ModButtonContext¶
Context provided to button methods:
interface ModButtonContext {
game: Game; // Game instance
clickedCell: { x: number; y: number } | null; // Clicked cell
myPlayer: Player | null; // Local player
uiState: unknown; // UI state info
}
Example: Donate Button¶
import { ModActionButton, ModButtonContext } from '@lands.io/mod-sdk';
export class DonateButton extends ModActionButton {
get icon() {
return '/assets/icons/donate.svg';
}
get label() {
return 'Donate Troops';
}
get intentName() {
return 'donate';
}
get cost() {
return undefined; // No gold cost
}
get fillColor() {
return '#3b82f6'; // Blue
}
get hoverFillColor() {
return '#2563eb';
}
shouldShow(context: ModButtonContext): boolean {
// Only show for alive players
if (!context.myPlayer?.isAlive()) return false;
// Only show when clicking on a teammate
if (!context.clickedCell) return false;
const clickedPlayer = context.game.playerAt(
context.clickedCell.x,
context.clickedCell.y
);
return (
clickedPlayer !== null && this.isTeammate(context.myPlayer, clickedPlayer)
);
}
isDisabled(context: ModButtonContext): boolean {
// Disable if not enough troops
return (context.myPlayer?.troops() ?? 0) < 100;
}
getPayload(context: ModButtonContext) {
const clickedPlayer = context.game.playerAt(
context.clickedCell!.x,
context.clickedCell!.y
);
return {
recipientId: clickedPlayer?.id(),
percentage: 10,
};
}
private isTeammate(player1: Player, player2: Player): boolean {
// Check team membership via modState
return false; // Implement based on your team logic
}
}
Handling Button Intents¶
Register an intent handler to process button clicks:
registerIntentHandlers(executor: Executor): void {
executor.registerModIntentHandler(executor.modId, 'donate', (intent) => {
const { recipientId, percentage } = intent.payload;
if (!recipientId || !percentage) {
return new NoOpExecution();
}
return new DonateExecution(
intent.playerID,
recipientId,
percentage,
this.modState
);
});
}