Actions¶
Actions define what players (and AI) can do in the game.
Overview¶
An Action represents an ability like attacking, building, or using a special power:
import {
BaseAction,
ActionContext,
ActionTarget,
Execution,
} from '@lands.io/mod-sdk';
class MyAction extends BaseAction {
readonly id = 'my-action';
readonly label = 'My Action';
canActivate(context: ActionContext): boolean {
return context.player.troops() > 1000;
}
chooseTarget(context: ActionContext): ActionTarget | null {
// AI targeting logic
return null;
}
createExecution(context: ActionContext, target: ActionTarget): Execution {
return new MyExecution(context.player.id(), target);
}
}
BaseAction Interface¶
Required Properties¶
Required Methods¶
// Can this action be used right now?
abstract canActivate(context: ActionContext): boolean;
// AI: Choose a target (return null for no action)
abstract chooseTarget(context: ActionContext): ActionTarget | null;
// Create the execution that modifies game state
abstract createExecution(context: ActionContext, target: ActionTarget): Execution;
Optional Methods¶
ActionContext¶
Provides context about the current game state:
interface ActionContext {
game: Game; // The game instance
player: Player; // The acting player
tick: number; // Current game tick
}
Registering Actions¶
Register in registerActions:
registerActions(executor: Executor): void {
executor.registerAction(new SpecialAttackAction());
executor.registerAction(new DefendAction());
}
Action Hooks¶
Modify existing actions without replacing them:
registerActions(executor: Executor): void {
// Block attacks on teammates
executor.registerActionHooks
.attack({
isValidTarget: (ctx, target, valid) => {
if (!valid) return false;
return !this.isTeammate(ctx.player, target);
}
})
.boat({
isValidTarget: (ctx, target, valid) => {
if (!valid) return false;
return !this.isTeammate(ctx.player, target);
}
});
}
Example: Team Attack Action¶
class TeamAttackAction extends BaseAction<Player> {
readonly id = 'team-attack';
readonly label = 'Team Attack';
canActivate(context: ActionContext): boolean {
// Can attack if we have troops and teammates nearby
return context.player.troops() > 100 && this.hasNearbyTeammates(context);
}
chooseTarget(context: ActionContext): Player | null {
// Find nearest enemy
const enemies = context.game
.players()
.filter((p) => !this.isTeammate(context.player, p))
.filter((p) => p.isAlive());
return this.findNearest(context.player, enemies);
}
createExecution(context: ActionContext, target: Player): Execution {
return new TeamAttackExecution(context.player.id(), target.id());
}
}