mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-04 13:36:09 +00:00
feat: multi-warship selection with Shift+drag box (#3677)
Resolves #3666 ## Description: Adds RTS-style box selection for warships. Hold Shift and drag (desktop) or long-press and drag (touch/mobile) to draw a selection rectangle — all player-owned warships inside get selected at once. A subsequent click/tap on water sends them all to that location. - `SelectionBoxLayer` — pixel-dashed rectangle in world-space, player territory color; shared between desktop and touch - `UILayer` — same pulsing selection outline on each box-selected warship; clears correctly when switching between single/multi selection - `UnitLayer` — finds warships in screen rect, filters inactive ships before sending; touch support included - `InputHandler` — Shift+drag and touch long-press+drag both emit selection box events; cursor becomes crosshair on Shift; discards active ghost structure on Shift press; configurable via `shiftKey` keybind - `Transport` — single atomic `move_multiple_warships` intent (no split on socket drop) - `Schemas` + `ExecutionManager` + `MoveMultipleWarshipsExecution` — server fans out atomic intent into individual `MoveWarshipExecution` per ship - `DynamicUILayer` — `MoveIndicatorUI` chevron animation on target tile for both single and multi move - `UnitDisplay` — warship tooltip Shift hint via `translateText` - `HelpModal` — new hotkey row: Shift + drag → select multiple warships ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## UI update ### Mouse + Keyboard https://github.com/user-attachments/assets/3f35ab5e-1f3c-4c5d-bc4f-aabccf64dc60 ### Touch https://github.com/user-attachments/assets/0d6aec3f-44fa-4fee-b5c6-b267b9b14d79 ## ## Please put your Discord username so you can be contacted if a bug or regression is found: fghjk_60845
This commit is contained in:
@@ -68,7 +68,7 @@ export class Executor {
|
||||
case "cancel_boat":
|
||||
return new BoatRetreatExecution(player, intent.unitID);
|
||||
case "move_warship":
|
||||
return new MoveWarshipExecution(player, intent.unitId, intent.tile);
|
||||
return new MoveWarshipExecution(player, intent.unitIds, intent.tile);
|
||||
case "spawn":
|
||||
return new SpawnExecution(this.gameID, player.info(), intent.tile);
|
||||
case "boat":
|
||||
|
||||
@@ -4,31 +4,36 @@ import { TileRef } from "../game/GameMap";
|
||||
export class MoveWarshipExecution implements Execution {
|
||||
constructor(
|
||||
private readonly owner: Player,
|
||||
private readonly unitId: number,
|
||||
private readonly unitIds: number[],
|
||||
private readonly position: TileRef,
|
||||
) {}
|
||||
|
||||
init(mg: Game, ticks: number): void {
|
||||
init(mg: Game, _ticks: number): void {
|
||||
if (!mg.isValidRef(this.position)) {
|
||||
console.warn(`MoveWarshipExecution: position ${this.position} not valid`);
|
||||
return;
|
||||
}
|
||||
const warship = this.owner
|
||||
.units(UnitType.Warship)
|
||||
.find((u) => u.id() === this.unitId);
|
||||
if (!warship) {
|
||||
console.warn("MoveWarshipExecution: warship not found");
|
||||
return;
|
||||
// Cache warship list and build a lookup map — avoids repeated iteration
|
||||
const warshipMap = new Map(
|
||||
this.owner.units(UnitType.Warship).map((u) => [u.id(), u]),
|
||||
);
|
||||
// Deduplicate ids so each warship is only moved once
|
||||
for (const unitId of new Set(this.unitIds)) {
|
||||
const warship = warshipMap.get(unitId);
|
||||
if (!warship) {
|
||||
console.warn(`MoveWarshipExecution: warship ${unitId} not found`);
|
||||
continue;
|
||||
}
|
||||
if (!warship.isActive()) {
|
||||
console.warn(`MoveWarshipExecution: warship ${unitId} is not active`);
|
||||
continue;
|
||||
}
|
||||
warship.setPatrolTile(this.position);
|
||||
warship.setTargetTile(undefined);
|
||||
}
|
||||
if (!warship.isActive()) {
|
||||
console.warn("MoveWarshipExecution: warship is not active");
|
||||
return;
|
||||
}
|
||||
warship.setPatrolTile(this.position);
|
||||
warship.setTargetTile(undefined);
|
||||
}
|
||||
|
||||
tick(ticks: number): void {}
|
||||
tick(_ticks: number): void {}
|
||||
|
||||
isActive(): boolean {
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user