1
0
Fork 0
This commit is contained in:
Michaël Lemaire 2018-07-12 16:16:39 +02:00
parent 4a7e50eaaa
commit f1c8fb5289
13 changed files with 79 additions and 55 deletions

View File

@ -42,6 +42,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
* Move animation should face the target when firing after
* 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)

View File

@ -64,14 +64,15 @@ module TK.SpaceTac {
}
measure(loc1: IArenaLocation, loc2: IArenaLocation): number {
// FIXME
let d = super.measure(loc1, loc2) / this.unit;
let r = Math.round(d);
if (r >= d) {
return Math.floor(d);
} else if (r - d < 1e-8) {
return Math.ceil(d);
} else if (d - r < 1e-8) {
return r;
} else {
return Math.ceil(d);
return Math.floor(d);
}
}
}

View File

@ -5,8 +5,9 @@ module TK.SpaceTac.Specs {
let ship = new Ship();
TestTools.setShipModel(ship, 100, 0, ship_ap);
TestTools.addEngine(ship, engine_distance);
let action = new TriggerAction("weapon", { power: weapon_ap, range: distance });
let action = new TriggerAction("weapon", { power: weapon_ap, range: distance, blast: 0.1 });
let simulator = new MoveFireSimulator(ship, new PixelGrid());
ship.actions.addCustom(action);
return [ship, simulator, action];
}
@ -28,7 +29,7 @@ module TK.SpaceTac.Specs {
test.case("fires directly when in range", check => {
let [ship, simulator, action] = simpleWeaponCase();
let result = simulator.simulateAction(action, new Target(ship.arena_x + 5, ship.arena_y, null));
let result = simulator.simulateAction(action, new Target(ship.arena_x + 5, ship.arena_y));
check.same(result.success, true, 'success');
check.same(result.need_move, false, 'need_move');
@ -37,13 +38,13 @@ module TK.SpaceTac.Specs {
check.same(result.total_fire_ap, 3, 'total_fire_ap');
check.equals(result.parts, [
{ action: action, target: new Target(ship.arena_x + 5, ship.arena_y, null), ap: 3, possible: true }
{ action: action, target: new Target(ship.arena_x + 5, ship.arena_y), ap: 3, possible: true }
]);
});
test.case("can't fire when in range, but not enough AP", check => {
let [ship, simulator, action] = simpleWeaponCase(10, 2, 3);
let result = simulator.simulateAction(action, new Target(ship.arena_x + 5, ship.arena_y, null));
let result = simulator.simulateAction(action, new Target(ship.arena_x + 5, ship.arena_y));
check.equals(result.success, true, 'success');
check.equals(result.need_move, false, 'need_move');
check.equals(result.need_fire, true, 'need_fire');
@ -51,18 +52,33 @@ module TK.SpaceTac.Specs {
check.equals(result.total_fire_ap, 3, 'total_fire_ap');
check.equals(result.parts, [
{ action: action, target: new Target(ship.arena_x + 5, ship.arena_y, null), ap: 3, possible: false }
{ action: action, target: new Target(ship.arena_x + 5, ship.arena_y), ap: 3, possible: false }
]);
});
test.case("can't fire at invalid target", check => {
let [ship, simulator, action] = simpleWeaponCase(10, 3, 3);
let result = simulator.simulateAction(action, new Target(ship.arena_x + 5, ship.arena_y));
check.equals(result.complete, true, 'complete');
check.equals(result.need_fire, true, 'need_fire');
check.equals(result.can_fire, true, 'can_fire');
check.in("with invalid target", check => {
check.patch(action, "checkTarget", () => false);
result = simulator.simulateAction(action, new Target(ship.arena_x + 5, ship.arena_y));
check.equals(result.complete, false, 'complete');
check.equals(result.need_fire, true, 'need_fire');
check.equals(result.can_fire, false, 'can_fire');
});
});
test.case("moves straight to get within range", check => {
let [ship, simulator, action] = simpleWeaponCase();
let result = simulator.simulateAction(action, new Target(ship.arena_x + 15, ship.arena_y, null));
let result = simulator.simulateAction(action, new Target(ship.arena_x + 15, ship.arena_y));
check.equals(result.success, true, 'success');
check.equals(result.need_move, true, 'need_move');
check.equals(result.can_move, true, 'can_move');
check.equals(result.can_end_move, true, 'can_end_move');
check.equals(result.move_location, new Target(ship.arena_x + 5, ship.arena_y, null));
check.equals(result.move_location, new Target(ship.arena_x + 5, ship.arena_y));
check.equals(result.total_move_ap, 1);
check.equals(result.need_fire, true, 'need_fire');
check.equals(result.can_fire, true, 'can_fire');
@ -70,8 +86,8 @@ module TK.SpaceTac.Specs {
let move_action = ship.actions.listAll().filter(action => action instanceof MoveAction)[0];
check.equals(result.parts, [
{ action: move_action, target: new Target(ship.arena_x + 5, ship.arena_y, null), ap: 1, possible: true },
{ action: action, target: new Target(ship.arena_x + 15, ship.arena_y, null), ap: 3, possible: true }
{ action: move_action, target: new Target(ship.arena_x + 5, ship.arena_y), ap: 1, possible: true },
{ action: action, target: new Target(ship.arena_x + 15, ship.arena_y), ap: 3, possible: true }
]);
});
@ -134,11 +150,11 @@ module TK.SpaceTac.Specs {
test.case("moves to get in range, even if not enough AP to fire", check => {
let [ship, simulator, action] = simpleWeaponCase(8, 3, 2, 5);
let result = simulator.simulateAction(action, new Target(ship.arena_x + 18, ship.arena_y, null));
let result = simulator.simulateAction(action, new Target(ship.arena_x + 18, ship.arena_y));
check.same(result.success, true, 'success');
check.same(result.need_move, true, 'need_move');
check.same(result.can_end_move, true, 'can_end_move');
check.equals(result.move_location, new Target(ship.arena_x + 10, ship.arena_y, null));
check.equals(result.move_location, new Target(ship.arena_x + 10, ship.arena_y));
check.equals(result.total_move_ap, 2);
check.same(result.need_fire, true, 'need_fire');
check.same(result.can_fire, false, 'can_fire');
@ -146,15 +162,15 @@ module TK.SpaceTac.Specs {
let move_action = ship.actions.listAll().filter(action => action instanceof MoveAction)[0];
check.equals(result.parts, [
{ action: move_action, target: new Target(ship.arena_x + 10, ship.arena_y, null), ap: 2, possible: true },
{ action: action, target: new Target(ship.arena_x + 18, ship.arena_y, null), ap: 2, possible: false }
{ action: move_action, target: new Target(ship.arena_x + 10, ship.arena_y), ap: 2, possible: true },
{ action: action, target: new Target(ship.arena_x + 18, ship.arena_y), ap: 2, possible: false }
]);
});
test.case("does nothing if trying to move in the same spot", check => {
let [ship, simulator, action] = simpleWeaponCase();
let move_action = ship.actions.listAll().filter(action => action instanceof MoveAction)[0];
let result = simulator.simulateAction(move_action, new Target(ship.arena_x, ship.arena_y, null));
let result = simulator.simulateAction(move_action, new Target(ship.arena_x, ship.arena_y));
check.equals(result.success, false);
check.equals(result.need_move, false);
check.equals(result.need_fire, false);
@ -163,10 +179,10 @@ module TK.SpaceTac.Specs {
test.case("does not move if already in range, even if in the safety margin", check => {
let [ship, simulator, action] = simpleWeaponCase(100);
let result = simulator.simulateAction(action, new Target(ship.arena_x + 97, ship.arena_y, null), 5);
let result = simulator.simulateAction(action, new Target(ship.arena_x + 97, ship.arena_y), 5);
check.equals(result.success, true);
check.equals(result.need_move, false);
result = simulator.simulateAction(action, new Target(ship.arena_x + 101, ship.arena_y, null), 5);
result = simulator.simulateAction(action, new Target(ship.arena_x + 101, ship.arena_y), 5);
check.equals(result.success, true);
check.equals(result.need_move, true);
check.equals(result.move_location, new Target(ship.arena_x + 6, ship.arena_y));

View File

@ -96,7 +96,7 @@ module TK.SpaceTac {
let candidates: [number, Target][] = [];
iforeach(this.scanCircle(target.x, target.y, radius), candidate => {
if (action.checkLocationTarget(this.ship, candidate)) {
if (action.checkTarget(this.ship, candidate)) {
candidates.push([candidate.getDistanceTo(this.ship.location), candidate]);
}
});
@ -166,7 +166,7 @@ module TK.SpaceTac {
} else {
result.need_fire = true;
result.total_fire_ap = action.getPowerUsage(this.ship, target);
result.can_fire = result.total_fire_ap <= ap;
result.can_fire = (action.checkTarget(this.ship, target, result.move_location)) && (result.total_fire_ap <= ap);
result.fire_location = target;
result.parts.push({ action: action, target: target, ap: result.total_fire_ap, possible: (!result.need_move || result.can_end_move) && result.can_fire });
result.success = true;

View File

@ -28,5 +28,13 @@ module TK.SpaceTac.Specs {
var t2 = Target.newFromLocation(4, 5);
check.nears(t1.getAngleTo(t2), Math.PI / 4);
});
test.case("snaps to a grid", check => {
let grid = new HexagonalArenaGrid(5, 1);
check.equals(Target.newFromLocation(1, 1).snap(grid), Target.newFromLocation(0, 0), "1,1");
check.equals(Target.newFromLocation(6, 4).snap(grid), Target.newFromLocation(7.5, 5), "6,4");
let ship = new Ship();
check.equals(new Target(6, 4, ship).snap(grid), new Target(7.5, 5, ship), "6,4,ship");
});
});
}

View File

@ -10,10 +10,10 @@ module TK.SpaceTac {
ship_id: RObjectId | null
// Standard constructor
constructor(x: number, y: number, ship: Ship | null = null) {
constructor(x: number, y: number, ship: Ship | RObjectId | null = null) {
this.x = x;
this.y = y;
this.ship_id = ship ? ship.id : null;
this.ship_id = (ship === null) ? null : rid(ship);
}
jasmineToString() {
@ -38,12 +38,8 @@ module TK.SpaceTac {
* Snap to battle grid
*/
snap(grid: ArenaGrid): Target {
if (this.ship_id) {
return this;
} else {
let location = grid.snap(this);
return Target.newFromLocation(location.x, location.y);
}
let location = grid.snap(this);
return new Target(location.x, location.y, this.ship_id);
}
// Get distance to another target

View File

@ -236,14 +236,14 @@ module TK.SpaceTac {
*
* Will call checkLocationTarget or checkShipTarget by default
*/
checkTarget(ship: Ship, target: Target): boolean {
checkTarget(ship: Ship, target: Target, from: IArenaLocation = ship.location): boolean {
if (this.checkCannotBeApplied(ship)) {
return false;
} else {
if (target.isShip()) {
return this.checkShipTarget(ship, target);
return this.checkShipTarget(ship, target, from);
} else {
return this.checkLocationTarget(ship, target);
return this.checkLocationTarget(ship, target, from);
}
}
}
@ -253,7 +253,7 @@ module TK.SpaceTac {
*
* Should not check for power or action availability, only whether the target is valid
*/
protected checkLocationTarget(ship: Ship, target: Target): boolean {
protected checkLocationTarget(ship: Ship, target: Target, from: IArenaLocation): boolean {
return false;
}
@ -262,7 +262,7 @@ module TK.SpaceTac {
*
* Should not check for power or action availability, only whether the target is valid
*/
protected checkShipTarget(ship: Ship, target: Target): boolean {
protected checkShipTarget(ship: Ship, target: Target, from: IArenaLocation): boolean {
return false;
}

View File

@ -75,7 +75,7 @@ module TK.SpaceTac {
return result;
}
checkShipTarget(ship: Ship, target: Target): boolean {
checkShipTarget(ship: Ship, target: Target, from: IArenaLocation): boolean {
if (ship.actions.isToggled(this)) {
return target.isShip(ship);
} else {
@ -83,11 +83,11 @@ module TK.SpaceTac {
}
}
checkLocationTarget(ship: Ship, target: Target): boolean {
checkLocationTarget(ship: Ship, target: Target, from: IArenaLocation): boolean {
if (ship.actions.isToggled(this)) {
return false;
} else {
return ship.grid.inRange(ship.location, target, this.deploy_distance);
return ship.grid.inRange(from, target, this.deploy_distance);
}
}

View File

@ -68,19 +68,19 @@ module TK.SpaceTac.Specs {
var action = new MoveAction("Engine", { distance_per_power: 1000 });
var result = action.checkLocationTarget(ship, Target.newFromLocation(700, 500));
var result = action.checkTarget(ship, Target.newFromLocation(700, 500));
check.equals(result, true);
result = action.checkLocationTarget(ship, Target.newFromLocation(800, 500));
result = action.checkTarget(ship, Target.newFromLocation(800, 500));
check.equals(result, true);
result = action.checkLocationTarget(ship, Target.newFromLocation(900, 500));
result = action.checkTarget(ship, Target.newFromLocation(900, 500));
check.equals(result, false);
result = action.checkLocationTarget(ship, Target.newFromLocation(1000, 500));
result = action.checkTarget(ship, Target.newFromLocation(1000, 500));
check.equals(result, false);
result = action.checkLocationTarget(ship, Target.newFromLocation(1200, 500));
result = action.checkTarget(ship, Target.newFromLocation(1200, 500));
check.equals(result, true);
});

View File

@ -90,8 +90,8 @@ module TK.SpaceTac {
return this.distance_per_power * ship.grid.getUnit();
}
checkLocationTarget(ship: Ship, target: Target): boolean {
if (!ship.grid.check(target) || ship.grid.measure(ship.location, target) < 1e-8) {
protected checkLocationTarget(ship: Ship, target: Target, from: IArenaLocation): boolean {
if (!ship.grid.check(target) || ship.grid.measure(from, target) < 1e-8) {
return false;
}

View File

@ -67,7 +67,7 @@ module TK.SpaceTac {
return result;
}
checkShipTarget(ship: Ship, target: Target): boolean {
checkShipTarget(ship: Ship, target: Target, from: IArenaLocation): boolean {
return ship.is(target.ship_id);
}

View File

@ -128,24 +128,24 @@ module TK.SpaceTac {
}
}
checkLocationTarget(ship: Ship, target: Target): boolean {
checkLocationTarget(ship: Ship, target: Target, from: IArenaLocation): boolean {
if (target && (this.blast > 0 || this.angle > 0)) {
return ship.grid.inRange(ship.location, target, this.range);
return ship.grid.inRange(from, target, this.range);
} else {
return false;
}
}
checkShipTarget(ship: Ship, target: Target): boolean {
checkShipTarget(ship: Ship, target: Target, from: IArenaLocation): boolean {
if (this.range > 0 && ship.is(target.ship_id)) {
// No self fire
return false;
} else {
// Check if target is in range
if (this.blast > 0 || this.angle > 0) {
return this.checkLocationTarget(ship, new Target(target.x, target.y));
return this.checkLocationTarget(ship, new Target(target.x, target.y), from);
} else {
return ship.grid.inRange(ship.location, target, this.range);
return ship.grid.inRange(from, target, this.range);
}
}
}

View File

@ -263,10 +263,12 @@ module TK.SpaceTac.UI {
this.updateImpactIndicators(this.impact_indicators, this.ship, this.action, this.target, this.simulation.move_location);
this.fire_arrow.setPosition(this.target.x, this.target.y);
this.fire_arrow.setRotation(angle);
this.view.changeImage(this.fire_arrow, simulation.complete ? "battle-hud-simulator-ok" : "battle-hud-simulator-power");
this.fire_arrow.visible = true;
if (this.mode != ActionTargettingMode.SURROUNDINGS) {
this.fire_arrow.setPosition(this.target.x, this.target.y);
this.fire_arrow.setRotation(angle);
this.view.changeImage(this.fire_arrow, simulation.complete ? "battle-hud-simulator-ok" : "battle-hud-simulator-power");
this.fire_arrow.visible = true;
}
} else {
this.impact_area.visible = false;
this.impact_indicators.visible = false;
@ -301,7 +303,7 @@ module TK.SpaceTac.UI {
move_action = <MoveAction>last_move.action;
}
} else {
let engine = new MoveFireSimulator(this.ship, new PixelGrid()).findEngine();
let engine = new MoveFireSimulator(this.ship, new ArenaGrid()).findEngine();
if (engine) {
move_action = engine;
}