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 * 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 * 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) * Improve arena ships layering (sometimes information is displayed behind other sprites)
* In the ship tooltip, show power cost, toggled and overheat states * In the ship tooltip, show power cost, toggled and overheat states
* Display shield (and its (dis)appearance) * Display shield (and its (dis)appearance)

View file

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

View file

@ -5,8 +5,9 @@ module TK.SpaceTac.Specs {
let ship = new Ship(); let ship = new Ship();
TestTools.setShipModel(ship, 100, 0, ship_ap); TestTools.setShipModel(ship, 100, 0, ship_ap);
TestTools.addEngine(ship, engine_distance); 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()); let simulator = new MoveFireSimulator(ship, new PixelGrid());
ship.actions.addCustom(action);
return [ship, simulator, action]; return [ship, simulator, action];
} }
@ -28,7 +29,7 @@ module TK.SpaceTac.Specs {
test.case("fires directly when in range", check => { test.case("fires directly when in range", check => {
let [ship, simulator, action] = simpleWeaponCase(); 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.success, true, 'success');
check.same(result.need_move, false, 'need_move'); 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.same(result.total_fire_ap, 3, 'total_fire_ap');
check.equals(result.parts, [ 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 => { test.case("can't fire when in range, but not enough AP", check => {
let [ship, simulator, action] = simpleWeaponCase(10, 2, 3); 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.success, true, 'success');
check.equals(result.need_move, false, 'need_move'); check.equals(result.need_move, false, 'need_move');
check.equals(result.need_fire, true, 'need_fire'); 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.total_fire_ap, 3, 'total_fire_ap');
check.equals(result.parts, [ 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 => { test.case("moves straight to get within range", check => {
let [ship, simulator, action] = simpleWeaponCase(); 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.success, true, 'success');
check.equals(result.need_move, true, 'need_move'); check.equals(result.need_move, true, 'need_move');
check.equals(result.can_move, true, 'can_move'); check.equals(result.can_move, true, 'can_move');
check.equals(result.can_end_move, true, 'can_end_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.total_move_ap, 1);
check.equals(result.need_fire, true, 'need_fire'); check.equals(result.need_fire, true, 'need_fire');
check.equals(result.can_fire, true, 'can_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]; let move_action = ship.actions.listAll().filter(action => action instanceof MoveAction)[0];
check.equals(result.parts, [ check.equals(result.parts, [
{ action: move_action, target: new Target(ship.arena_x + 5, ship.arena_y, null), ap: 1, 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, null), ap: 3, 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 => { 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 [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.success, true, 'success');
check.same(result.need_move, true, 'need_move'); check.same(result.need_move, true, 'need_move');
check.same(result.can_end_move, true, 'can_end_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.equals(result.total_move_ap, 2);
check.same(result.need_fire, true, 'need_fire'); check.same(result.need_fire, true, 'need_fire');
check.same(result.can_fire, false, 'can_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]; let move_action = ship.actions.listAll().filter(action => action instanceof MoveAction)[0];
check.equals(result.parts, [ check.equals(result.parts, [
{ action: move_action, target: new Target(ship.arena_x + 10, ship.arena_y, null), ap: 2, possible: true }, { 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, null), ap: 2, possible: false } { 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 => { test.case("does nothing if trying to move in the same spot", check => {
let [ship, simulator, action] = simpleWeaponCase(); let [ship, simulator, action] = simpleWeaponCase();
let move_action = ship.actions.listAll().filter(action => action instanceof MoveAction)[0]; 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.success, false);
check.equals(result.need_move, false); check.equals(result.need_move, false);
check.equals(result.need_fire, 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 => { test.case("does not move if already in range, even if in the safety margin", check => {
let [ship, simulator, action] = simpleWeaponCase(100); 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.success, true);
check.equals(result.need_move, false); 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.success, true);
check.equals(result.need_move, true); check.equals(result.need_move, true);
check.equals(result.move_location, new Target(ship.arena_x + 6, ship.arena_y)); 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][] = []; let candidates: [number, Target][] = [];
iforeach(this.scanCircle(target.x, target.y, radius), candidate => { 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]); candidates.push([candidate.getDistanceTo(this.ship.location), candidate]);
} }
}); });
@ -166,7 +166,7 @@ module TK.SpaceTac {
} else { } else {
result.need_fire = true; result.need_fire = true;
result.total_fire_ap = action.getPowerUsage(this.ship, target); 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.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.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; result.success = true;

View file

@ -28,5 +28,13 @@ module TK.SpaceTac.Specs {
var t2 = Target.newFromLocation(4, 5); var t2 = Target.newFromLocation(4, 5);
check.nears(t1.getAngleTo(t2), Math.PI / 4); 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 ship_id: RObjectId | null
// Standard constructor // 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.x = x;
this.y = y; this.y = y;
this.ship_id = ship ? ship.id : null; this.ship_id = (ship === null) ? null : rid(ship);
} }
jasmineToString() { jasmineToString() {
@ -38,12 +38,8 @@ module TK.SpaceTac {
* Snap to battle grid * Snap to battle grid
*/ */
snap(grid: ArenaGrid): Target { snap(grid: ArenaGrid): Target {
if (this.ship_id) { let location = grid.snap(this);
return this; return new Target(location.x, location.y, this.ship_id);
} else {
let location = grid.snap(this);
return Target.newFromLocation(location.x, location.y);
}
} }
// Get distance to another target // Get distance to another target

View file

@ -236,14 +236,14 @@ module TK.SpaceTac {
* *
* Will call checkLocationTarget or checkShipTarget by default * 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)) { if (this.checkCannotBeApplied(ship)) {
return false; return false;
} else { } else {
if (target.isShip()) { if (target.isShip()) {
return this.checkShipTarget(ship, target); return this.checkShipTarget(ship, target, from);
} else { } 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 * 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; return false;
} }
@ -262,7 +262,7 @@ module TK.SpaceTac {
* *
* Should not check for power or action availability, only whether the target is valid * 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; return false;
} }

View file

@ -75,7 +75,7 @@ module TK.SpaceTac {
return result; return result;
} }
checkShipTarget(ship: Ship, target: Target): boolean { checkShipTarget(ship: Ship, target: Target, from: IArenaLocation): boolean {
if (ship.actions.isToggled(this)) { if (ship.actions.isToggled(this)) {
return target.isShip(ship); return target.isShip(ship);
} else { } 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)) { if (ship.actions.isToggled(this)) {
return false; return false;
} else { } 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 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); check.equals(result, true);
result = action.checkLocationTarget(ship, Target.newFromLocation(800, 500)); result = action.checkTarget(ship, Target.newFromLocation(800, 500));
check.equals(result, true); check.equals(result, true);
result = action.checkLocationTarget(ship, Target.newFromLocation(900, 500)); result = action.checkTarget(ship, Target.newFromLocation(900, 500));
check.equals(result, false); check.equals(result, false);
result = action.checkLocationTarget(ship, Target.newFromLocation(1000, 500)); result = action.checkTarget(ship, Target.newFromLocation(1000, 500));
check.equals(result, false); check.equals(result, false);
result = action.checkLocationTarget(ship, Target.newFromLocation(1200, 500)); result = action.checkTarget(ship, Target.newFromLocation(1200, 500));
check.equals(result, true); check.equals(result, true);
}); });

View file

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

View file

@ -67,7 +67,7 @@ module TK.SpaceTac {
return result; return result;
} }
checkShipTarget(ship: Ship, target: Target): boolean { checkShipTarget(ship: Ship, target: Target, from: IArenaLocation): boolean {
return ship.is(target.ship_id); 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)) { 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 { } else {
return false; 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)) { if (this.range > 0 && ship.is(target.ship_id)) {
// No self fire // No self fire
return false; return false;
} else { } else {
// Check if target is in range // Check if target is in range
if (this.blast > 0 || this.angle > 0) { 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 { } 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.updateImpactIndicators(this.impact_indicators, this.ship, this.action, this.target, this.simulation.move_location);
this.fire_arrow.setPosition(this.target.x, this.target.y); if (this.mode != ActionTargettingMode.SURROUNDINGS) {
this.fire_arrow.setRotation(angle); this.fire_arrow.setPosition(this.target.x, this.target.y);
this.view.changeImage(this.fire_arrow, simulation.complete ? "battle-hud-simulator-ok" : "battle-hud-simulator-power"); this.fire_arrow.setRotation(angle);
this.fire_arrow.visible = true; this.view.changeImage(this.fire_arrow, simulation.complete ? "battle-hud-simulator-ok" : "battle-hud-simulator-power");
this.fire_arrow.visible = true;
}
} else { } else {
this.impact_area.visible = false; this.impact_area.visible = false;
this.impact_indicators.visible = false; this.impact_indicators.visible = false;
@ -301,7 +303,7 @@ module TK.SpaceTac.UI {
move_action = <MoveAction>last_move.action; move_action = <MoveAction>last_move.action;
} }
} else { } else {
let engine = new MoveFireSimulator(this.ship, new PixelGrid()).findEngine(); let engine = new MoveFireSimulator(this.ship, new ArenaGrid()).findEngine();
if (engine) { if (engine) {
move_action = engine; move_action = engine;
} }