diff --git a/TODO.md b/TODO.md index 186020b..727f628 100644 --- a/TODO.md +++ b/TODO.md @@ -41,6 +41,7 @@ Battle ------ * Fix tactical information being hidden when changing selected action +* Right click while targetting switch to edit mode (move target and fire target are then draggable) - this will be the default on mobile * Improve arena ships layering (sometimes information is displayed behind other sprites) * In the ship tooltip, show power cost, toggled and overheat states * Display shield (and its (dis)appearance) diff --git a/src/core/ArenaGrid.spec.ts b/src/core/ArenaGrid.spec.ts index c2cd018..0834bfa 100644 --- a/src/core/ArenaGrid.spec.ts +++ b/src/core/ArenaGrid.spec.ts @@ -5,6 +5,18 @@ module TK.SpaceTac.Specs { } testing("HexagonalArenaGrid", test => { + test.case("checks coordinates", check => { + let grid = new HexagonalArenaGrid(5, 1); + check.equals(grid.check({ x: 0, y: 0 }), true, "0,0"); + check.equals(grid.check({ x: 1, y: 0 }), false, "1,0"); + check.equals(grid.check({ x: 5, y: 0 }), true, "5,0"); + check.equals(grid.check({ x: 6, y: 0 }), false, "6,0"); + check.equals(grid.check({ x: 0, y: 5 }), false, "0,5"); + check.equals(grid.check({ x: 2.5, y: 5 }), true, "2.5,5"); + check.equals(grid.check({ x: 5, y: 5 }), false, "5,5"); + check.equals(grid.check({ x: 7.5, y: 5 }), true, "7.5,5"); + }); + test.case("snaps coordinates to the nearest grid point, on a biased grid", check => { let grid = new HexagonalArenaGrid(4, 0.75); checkLocation(check, grid.snap({ x: 0, y: 0 }), 0, 0); diff --git a/src/core/ArenaGrid.ts b/src/core/ArenaGrid.ts index e074871..793e7d0 100644 --- a/src/core/ArenaGrid.ts +++ b/src/core/ArenaGrid.ts @@ -2,21 +2,59 @@ module TK.SpaceTac { /** * Abstract grid for the arena where the battle takes place * - * The grid is used to snap arena coordinates for ships and targets + * The grid is used to snap arena coordinates on grid vertices, for ships and targets + * + * The default implementation does not enforce any grid or unit (leaves coordinates as they are) */ - export interface IArenaGrid { - snap(loc: IArenaLocation): IArenaLocation; + export class ArenaGrid { + /** + * Get the base unit of measurement between two points + */ + getUnit(): number { + return 1; + } + + /** + * Check that an arena location is on a grid vertex + */ + check(loc: IArenaLocation): boolean { + return arenaDistance(loc, this.snap(loc)) < 1e-8; + } + + /** + * Snap a floating point arena location to a grid vertex + */ + snap(loc: IArenaLocation): IArenaLocation { + return loc; + } + + /** + * Measure the distance between two points + * + * This returns a distance in grid units + */ + measure(loc1: IArenaLocation, loc2: IArenaLocation): number { + return arenaDistance(this.snap(loc1), this.snap(loc2)); + } } /** - * Pixel grid + * Pixel unbounded grid * - * This will only round the coordinates to the pixels + * This will only round the coordinates to the pixels, with an optional unit for distance measurements */ - export class PixelGrid implements IArenaGrid { + export class PixelGrid extends ArenaGrid { + constructor(protected readonly unit = 1) { + super(); + } + snap(loc: IArenaLocation): IArenaLocation { return new ArenaLocation(Math.round(loc.x), Math.round(loc.y)); } + + measure(loc1: IArenaLocation, loc2: IArenaLocation): number { + return Math.round(super.measure(loc1, loc2) / this.unit); + } } /** @@ -24,10 +62,12 @@ module TK.SpaceTac { * * This grid is composed of regular hexagons where all vertices are at a same distance "unit" of the hexagon center */ - export class HexagonalArenaGrid implements IArenaGrid { - private yunit: number; + export class HexagonalArenaGrid extends PixelGrid { + private readonly yunit: number; + + constructor(unit: number, yfactor = Math.sqrt(0.75)) { + super(unit); - constructor(private unit: number, private yfactor = Math.sqrt(0.75)) { this.yunit = unit * yfactor; } diff --git a/src/core/Battle.ts b/src/core/Battle.ts index bfb930b..7b12117 100644 --- a/src/core/Battle.ts +++ b/src/core/Battle.ts @@ -4,7 +4,7 @@ module TK.SpaceTac { */ export class Battle { // Grid for the arena - grid: IArenaGrid + grid: ArenaGrid // Battle outcome, if the battle has ended outcome: BattleOutcome | null = null @@ -34,8 +34,6 @@ module TK.SpaceTac { // Size of the battle area width: number height: number - border = 50 - ship_separation = 100 // Indicator that an AI is playing ai_playing = false diff --git a/src/core/MoveFireSimulator.spec.ts b/src/core/MoveFireSimulator.spec.ts index 28c3d1a..d5d2d51 100644 --- a/src/core/MoveFireSimulator.spec.ts +++ b/src/core/MoveFireSimulator.spec.ts @@ -115,8 +115,6 @@ module TK.SpaceTac.Specs { battle.fleets[0].addShip(ship); let ship1 = battle.fleets[0].addShip(); let moveaction = nn(simulator.findEngine()); - (moveaction).safety_distance = 30; - battle.ship_separation = 30; check.same(simulator.getApproach(moveaction, Target.newFromLocation(350, 200), 100), ApproachSimulationError.NO_MOVE_NEEDED); check.same(simulator.getApproach(moveaction, Target.newFromLocation(400, 200), 100), ApproachSimulationError.NO_MOVE_NEEDED); diff --git a/src/core/MoveFireSimulator.ts b/src/core/MoveFireSimulator.ts index 11cdb88..f024828 100644 --- a/src/core/MoveFireSimulator.ts +++ b/src/core/MoveFireSimulator.ts @@ -50,7 +50,7 @@ module TK.SpaceTac { // Playing ship private ship: Ship, // Coordinates grid - private grid: IArenaGrid + private grid: ArenaGrid ) { } /** diff --git a/src/core/Ship.ts b/src/core/Ship.ts index f2b1687..e218cf1 100644 --- a/src/core/Ship.ts +++ b/src/core/Ship.ts @@ -78,6 +78,18 @@ module TK.SpaceTac { return new ArenaLocationAngle(this.arena_x, this.arena_y, this.arena_angle); } + /** + * Return the current grid for the ship + */ + get grid(): ArenaGrid { + let battle = this.getBattle(); + if (battle) { + return battle.grid; + } else { + return new ArenaGrid(); + } + } + /** * Returns the name of this ship */ diff --git a/src/core/Target.ts b/src/core/Target.ts index d5d34f7..8c074b9 100644 --- a/src/core/Target.ts +++ b/src/core/Target.ts @@ -37,7 +37,7 @@ module TK.SpaceTac { /** * Snap to battle grid */ - snap(grid: IArenaGrid): Target { + snap(grid: ArenaGrid): Target { if (this.ship_id) { return this; } else { diff --git a/src/core/actions/MoveAction.ts b/src/core/actions/MoveAction.ts index cd3bf92..623d918 100644 --- a/src/core/actions/MoveAction.ts +++ b/src/core/actions/MoveAction.ts @@ -75,7 +75,7 @@ module TK.SpaceTac { if (this.distance_per_power == 0) { return Infinity; } else if (target) { - let distance = Target.newFromShip(ship).getDistanceTo(target); + let distance = ship.grid.measure(ship.location, target); return Math.ceil(distance / this.distance_per_power); } else { return 0; @@ -83,19 +83,16 @@ module TK.SpaceTac { } getRangeRadius(ship: Ship): number { - return this.getRangeRadiusForPower(ship); - } - - /** - * Get the distance reachable with a given power - */ - getRangeRadiusForPower(ship: Ship, power = ship.getValue("power")): number { - return power * this.distance_per_power; + return ship.getValue("power") * this.distance_per_power * ship.grid.getUnit(); } checkLocationTarget(ship: Ship, target: Target): boolean { - // TODO Check it's on the grid + if (!ship.grid.check(target)) { + return false; + } + // TODO Check the space is not occupied + return true; } diff --git a/src/core/models/ModelAvenger.ts b/src/core/models/ModelAvenger.ts index 485103a..4d0a6f4 100644 --- a/src/core/models/ModelAvenger.ts +++ b/src/core/models/ModelAvenger.ts @@ -12,7 +12,7 @@ module TK.SpaceTac { getLevelUpgrades(level: number): ShipUpgrade[] { let engine = new MoveAction("Engine", { - distance_per_power: 60, + distance_per_power: 1, }); engine.configureCooldown(1, 1); diff --git a/src/core/models/ModelBreeze.ts b/src/core/models/ModelBreeze.ts index 8faf5d7..1788fe1 100644 --- a/src/core/models/ModelBreeze.ts +++ b/src/core/models/ModelBreeze.ts @@ -13,7 +13,7 @@ module TK.SpaceTac { getLevelUpgrades(level: number): ShipUpgrade[] { if (level == 1) { let engine = new MoveAction("Engine", { - distance_per_power: 460, + distance_per_power: 9, }); engine.configureCooldown(2, 1); diff --git a/src/core/models/ModelCommodore.ts b/src/core/models/ModelCommodore.ts index eadae10..d529012 100644 --- a/src/core/models/ModelCommodore.ts +++ b/src/core/models/ModelCommodore.ts @@ -13,7 +13,7 @@ module TK.SpaceTac { getLevelUpgrades(level: number): ShipUpgrade[] { if (level == 1) { let engine = new MoveAction("Engine", { - distance_per_power: 120, + distance_per_power: 3, }); let laser = new TriggerAction("Wingspan Laser", { diff --git a/src/core/models/ModelCreeper.ts b/src/core/models/ModelCreeper.ts index affc6e8..2528692 100644 --- a/src/core/models/ModelCreeper.ts +++ b/src/core/models/ModelCreeper.ts @@ -13,7 +13,7 @@ module TK.SpaceTac { getLevelUpgrades(level: number): ShipUpgrade[] { if (level == 1) { let engine = new MoveAction("Engine", { - distance_per_power: 240, + distance_per_power: 5, }); let gatling = new TriggerAction("Gatling Gun", { diff --git a/src/core/models/ModelFalcon.ts b/src/core/models/ModelFalcon.ts index 3c0859d..113cbe6 100644 --- a/src/core/models/ModelFalcon.ts +++ b/src/core/models/ModelFalcon.ts @@ -13,7 +13,7 @@ module TK.SpaceTac { getLevelUpgrades(level: number): ShipUpgrade[] { if (level == 1) { let engine = new MoveAction("Engine", { - distance_per_power: 130, + distance_per_power: 3, }); let missile = new TriggerAction("SubMunition Missile", { diff --git a/src/core/models/ModelFlea.ts b/src/core/models/ModelFlea.ts index 92ea6c2..433762f 100644 --- a/src/core/models/ModelFlea.ts +++ b/src/core/models/ModelFlea.ts @@ -13,7 +13,7 @@ module TK.SpaceTac { getLevelUpgrades(level: number): ShipUpgrade[] { if (level == 1) { let engine = new MoveAction("Main Engine", { - distance_per_power: 420, + distance_per_power: 8, }); let depleter = new TriggerAction("Power Depleter", { diff --git a/src/core/models/ModelJumper.ts b/src/core/models/ModelJumper.ts index 4fbe80a..cdbc2a2 100644 --- a/src/core/models/ModelJumper.ts +++ b/src/core/models/ModelJumper.ts @@ -13,7 +13,7 @@ module TK.SpaceTac { getLevelUpgrades(level: number): ShipUpgrade[] { if (level == 1) { let engine = new MoveAction("Engine", { - distance_per_power: 310, + distance_per_power: 6, }); let missile = new TriggerAction("SubMunition Missile", { diff --git a/src/core/models/ModelRhino.ts b/src/core/models/ModelRhino.ts index 7e224ef..24fec00 100644 --- a/src/core/models/ModelRhino.ts +++ b/src/core/models/ModelRhino.ts @@ -13,7 +13,7 @@ module TK.SpaceTac { getLevelUpgrades(level: number): ShipUpgrade[] { if (level == 1) { let engine = new MoveAction("Engine", { - distance_per_power: 120, + distance_per_power: 2, }); let gatling = new TriggerAction("Gatling Gun", { diff --git a/src/core/models/ModelTomahawk.ts b/src/core/models/ModelTomahawk.ts index ad849e9..2fa91d9 100644 --- a/src/core/models/ModelTomahawk.ts +++ b/src/core/models/ModelTomahawk.ts @@ -13,7 +13,7 @@ module TK.SpaceTac { getLevelUpgrades(level: number): ShipUpgrade[] { if (level == 1) { let engine = new MoveAction("Engine", { - distance_per_power: 120, + distance_per_power: 2, }); let gatling1 = new TriggerAction("Primary Gatling", { diff --git a/src/core/models/ModelTrapper.ts b/src/core/models/ModelTrapper.ts index 17ef046..6a02b65 100644 --- a/src/core/models/ModelTrapper.ts +++ b/src/core/models/ModelTrapper.ts @@ -13,7 +13,7 @@ module TK.SpaceTac { getLevelUpgrades(level: number): ShipUpgrade[] { if (level == 1) { let engine = new MoveAction("Engine", { - distance_per_power: 220, + distance_per_power: 3, }); engine.configureCooldown(1, 1); diff --git a/src/core/models/ModelXander.ts b/src/core/models/ModelXander.ts index b4294f6..da56408 100644 --- a/src/core/models/ModelXander.ts +++ b/src/core/models/ModelXander.ts @@ -13,7 +13,7 @@ module TK.SpaceTac { getLevelUpgrades(level: number): ShipUpgrade[] { if (level == 1) { let engine = new MoveAction("Engine", { - distance_per_power: 280, + distance_per_power: 5, }); let laser = new TriggerAction("Prokhorov Laser", { @@ -29,7 +29,7 @@ module TK.SpaceTac { hull.configureCooldown(1, 4); let disengage = new MoveAction("Disengage", { - distance_per_power: 1000, + distance_per_power: 20, }, "ionthruster"); disengage.configureCooldown(1, 3);