diff --git a/TODO b/TODO index ca94cbb..5dabd26 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,4 @@ +* Enable strict null checking in typescript * Ensure that tweens and particle emitters get destroyed once animation is done (or view changes) * Highlight ships that will be included as target of current action * Controls: Do not focus on ship while targetting for area effects (dissociate hover and target) @@ -27,7 +28,6 @@ * TacticalAI: allow to play several moves in the same turn * TacticalAI: add pauses to not play too quickly * TacticalAI: replace BullyAI -* AIDuel: fix first AI always winning when two identical AIs are selected * Add a defeat screen (game over for now) * Add a victory screen, with loot display * Add retreat from battle diff --git a/src/core/MoveFireSimulator.spec.ts b/src/core/MoveFireSimulator.spec.ts index 3531a2a..3b94779 100644 --- a/src/core/MoveFireSimulator.spec.ts +++ b/src/core/MoveFireSimulator.spec.ts @@ -89,5 +89,14 @@ module TS.SpaceTac.Specs { { action: jasmine.objectContaining({ code: "fire-null" }), target: new Target(ship.arena_x + 18, ship.arena_y, null), ap: 2 } ]); }); + + it("does nothing if trying to move in the same spot", function () { + let [ship, simulator, action] = simpleWeaponCase(); + let result = simulator.simulateAction(ship.listEquipment(SlotType.Engine)[0].action, new Target(ship.arena_x, ship.arena_y, null)); + expect(result.success).toBe(true); + expect(result.need_move).toBe(false); + expect(result.need_fire).toBe(false); + expect(result.parts).toEqual([]); + }); }); } diff --git a/src/core/MoveFireSimulator.ts b/src/core/MoveFireSimulator.ts index 4c1c9bb..ef0593c 100644 --- a/src/core/MoveFireSimulator.ts +++ b/src/core/MoveFireSimulator.ts @@ -59,27 +59,32 @@ module TS.SpaceTac { * Simulate a given action on a given valid target. */ simulateAction(action: BaseAction, target: Target): MoveFireResult { + let result = new MoveFireResult(); + let dx = target.x - this.ship.arena_x; let dy = target.y - this.ship.arena_y; let distance = Math.sqrt(dx * dx + dy * dy); - let result = new MoveFireResult(); + let ap = this.ship.values.power.get(); let action_radius = action.getRangeRadius(this.ship); if (action instanceof MoveAction || distance > action_radius) { - result.need_move = true; let move_distance = action instanceof MoveAction ? distance : distance - action_radius; - let move_target = new Target(this.ship.arena_x + dx * move_distance / distance, this.ship.arena_y + dy * move_distance / distance, null); - let engine = this.findBestEngine(); - if (engine) { - result.total_move_ap = engine.action.getActionPointsUsage(this.ship.getBattle(), this.ship, move_target); - result.can_move = ap > 0; - result.can_end_move = result.total_move_ap <= ap; - result.move_location = move_target; - result.parts.push({ action: engine.action, target: move_target, ap: result.total_move_ap }); + if (move_distance > 0.000001) { + result.need_move = true; - ap -= result.total_move_ap; - distance -= move_distance; + let move_target = new Target(this.ship.arena_x + dx * move_distance / distance, this.ship.arena_y + dy * move_distance / distance, null); + let engine = this.findBestEngine(); + if (engine) { + result.total_move_ap = engine.action.getActionPointsUsage(this.ship, move_target); + result.can_move = ap > 0; + result.can_end_move = result.total_move_ap <= ap; + result.move_location = move_target; + result.parts.push({ action: engine.action, target: move_target, ap: result.total_move_ap }); + + ap -= result.total_move_ap; + distance -= move_distance; + } } } @@ -87,7 +92,7 @@ module TS.SpaceTac { result.success = true; if (!(action instanceof MoveAction)) { result.need_fire = true; - result.total_fire_ap = action.getActionPointsUsage(this.ship.getBattle(), this.ship, target); + result.total_fire_ap = action.getActionPointsUsage(this.ship, target); result.can_fire = result.total_fire_ap <= ap; result.fire_location = target; result.parts.push({ action: action, target: target, ap: result.total_fire_ap }); diff --git a/src/core/actions/BaseAction.spec.ts b/src/core/actions/BaseAction.spec.ts index 579b45b..3abb062 100644 --- a/src/core/actions/BaseAction.spec.ts +++ b/src/core/actions/BaseAction.spec.ts @@ -8,22 +8,22 @@ module TS.SpaceTac { ship.addSlot(SlotType.Hull).attach(equipment); ship.values.power.setMaximal(10); - expect(action.canBeUsed(null, ship)).toBe(false); + expect(action.checkCannotBeApplied(ship)).toBe("not enough power"); ship.values.power.set(5); - expect(action.canBeUsed(null, ship)).toBe(true); - expect(action.canBeUsed(null, ship, 4)).toBe(true); - expect(action.canBeUsed(null, ship, 3)).toBe(true); - expect(action.canBeUsed(null, ship, 2)).toBe(false); + expect(action.checkCannotBeApplied(ship)).toBe(null); + expect(action.checkCannotBeApplied(ship, 4)).toBe(null); + expect(action.checkCannotBeApplied(ship, 3)).toBe(null); + expect(action.checkCannotBeApplied(ship, 2)).toBe("not enough power"); ship.values.power.set(3); - expect(action.canBeUsed(null, ship)).toBe(true); + expect(action.checkCannotBeApplied(ship)).toBe(null); ship.values.power.set(2); - expect(action.canBeUsed(null, ship)).toBe(false); + expect(action.checkCannotBeApplied(ship)).toBe("not enough power"); }); }); } diff --git a/src/core/actions/BaseAction.ts b/src/core/actions/BaseAction.ts index a364e05..f527efd 100644 --- a/src/core/actions/BaseAction.ts +++ b/src/core/actions/BaseAction.ts @@ -21,12 +21,18 @@ module TS.SpaceTac { this.equipment = equipment; } - // Check basic conditions to know if the ship can use this action at all - // Method to reimplement to set conditions - canBeUsed(battle: Battle, ship: Ship, remaining_ap: number = null): boolean { + /** + * Check basic conditions to know if the ship can use this action at all + * + * Method to extend to set conditions + * + * Returns an informative message indicating why the action cannot be used, null otherwise + */ + checkCannotBeApplied(ship: Ship, remaining_ap: number = null): string | null { + let battle = ship.getBattle(); if (battle && battle.playing_ship !== ship) { // Ship is not playing - return false; + return "ship not playing"; } // Check AP usage @@ -34,11 +40,15 @@ module TS.SpaceTac { remaining_ap = ship.values.power.get(); } var ap_usage = this.equipment ? this.equipment.ap_usage : 0; - return remaining_ap >= ap_usage; + if (remaining_ap >= ap_usage) { + return null; + } else { + return "not enough power"; + } } // Get the number of action points the action applied to a target would use - getActionPointsUsage(battle: Battle, ship: Ship, target: Target): number { + getActionPointsUsage(ship: Ship, target: Target): number { if (this.equipment) { return this.equipment.ap_usage; } else { @@ -66,14 +76,14 @@ module TS.SpaceTac { // Method to check if a target is applicable for this action // Will call checkLocationTarget or checkShipTarget by default - checkTarget(battle: Battle, ship: Ship, target: Target): Target { - if (!this.canBeUsed(battle, ship)) { + checkTarget(ship: Ship, target: Target): Target { + if (this.checkCannotBeApplied(ship)) { return null; } else if (target) { if (target.ship) { - return this.checkShipTarget(battle, ship, target); + return this.checkShipTarget(ship, target); } else { - return this.checkLocationTarget(battle, ship, target); + return this.checkLocationTarget(ship, target); } } else { return null; @@ -82,38 +92,42 @@ module TS.SpaceTac { // Method to reimplement to check if a space target is applicable // Must return null if the target can't be applied, an altered target, or the original target - checkLocationTarget(battle: Battle, ship: Ship, target: Target): Target { + checkLocationTarget(ship: Ship, target: Target): Target { return null; } // Method to reimplement to check if a ship target is applicable // Must return null if the target can't be applied, an altered target, or the original target - checkShipTarget(battle: Battle, ship: Ship, target: Target): Target { + checkShipTarget(ship: Ship, target: Target): Target { return null; } // Apply an action, returning true if it was successful - apply(battle: Battle, ship: Ship, target: Target): boolean { - if (this.canBeUsed(battle, ship)) { - target = this.checkTarget(battle, ship, target); + apply(ship: Ship, target: Target): boolean { + let reject = this.checkCannotBeApplied(ship); + if (reject == null) { + target = this.checkTarget(ship, target); if (!target && this.needs_target) { + console.warn("Action rejected - no target selected", ship, this, target); return false; } - let cost = this.getActionPointsUsage(battle, ship, target); + let cost = this.getActionPointsUsage(ship, target); if (!ship.useActionPoints(cost)) { + console.warn("Action rejected - not enough power", ship, this, target); return false; } - this.customApply(battle, ship, target); + this.customApply(ship, target); return true; } else { + console.warn(`Action rejected - ${reject}`, ship, this, target); return false; } } // Method to reimplement to apply a action - protected customApply(battle: Battle, ship: Ship, target: Target) { + protected customApply(ship: Ship, target: Target) { } } } diff --git a/src/core/actions/DeployDroneAction.spec.ts b/src/core/actions/DeployDroneAction.spec.ts index bc93ec2..9893c89 100644 --- a/src/core/actions/DeployDroneAction.spec.ts +++ b/src/core/actions/DeployDroneAction.spec.ts @@ -20,18 +20,18 @@ module TS.SpaceTac { equipment.ap_usage = 0; let action = new DeployDroneAction(equipment); - expect(action.checkTarget(null, ship, new Target(8, 0, null))).toEqual(new Target(8, 0, null)); - expect(action.checkTarget(null, ship, new Target(12, 0, null))).toEqual(new Target(8, 0, null)); + expect(action.checkTarget(ship, new Target(8, 0, null))).toEqual(new Target(8, 0, null)); + expect(action.checkTarget(ship, new Target(12, 0, null))).toEqual(new Target(8, 0, null)); let other = new Ship(); other.setArenaPosition(8, 0); - expect(action.checkTarget(null, ship, new Target(8, 0, other))).toBeNull(); + expect(action.checkTarget(ship, new Target(8, 0, other))).toBeNull(); }); it("deploys a new drone", function () { - let ship = new Ship(); - ship.setArenaPosition(0, 0); let battle = new Battle(); + let ship = battle.fleets[0].addShip(); + ship.setArenaPosition(0, 0); battle.playing_ship = ship; TestTools.setShipAP(ship, 3); let equipment = new Equipment(); @@ -43,7 +43,9 @@ module TS.SpaceTac { equipment.target_effects.push(new DamageEffect(50)); let action = new DeployDroneAction(equipment); - let result = action.apply(battle, ship, new Target(5, 0, null)); + battle.log.clear(); + battle.log.addFilter("value"); + let result = action.apply(ship, new Target(5, 0, null)); expect(result).toBe(true); expect(battle.drones.length).toBe(1); diff --git a/src/core/actions/DeployDroneAction.ts b/src/core/actions/DeployDroneAction.ts index a285f14..e403531 100644 --- a/src/core/actions/DeployDroneAction.ts +++ b/src/core/actions/DeployDroneAction.ts @@ -9,20 +9,24 @@ module TS.SpaceTac { super("deploy-" + equipment.code, "Deploy", true, equipment); } - checkLocationTarget(battle: Battle, ship: Ship, target: Target): Target { + checkLocationTarget(ship: Ship, target: Target): Target { // TODO Not too close to other ships and drones target = target.constraintInRange(ship.arena_x, ship.arena_y, this.equipment.distance); return target; } - protected customApply(battle: Battle, ship: Ship, target: Target) { + protected customApply(ship: Ship, target: Target) { let drone = new Drone(ship, this.equipment.code); drone.x = target.x; drone.y = target.y; drone.radius = this.equipment.blast; drone.effects = this.equipment.target_effects; drone.duration = this.equipment.duration; - battle.addDrone(drone); + + let battle = ship.getBattle(); + if (battle) { + battle.addDrone(drone); + } } } } diff --git a/src/core/actions/EndTurnAction.spec.ts b/src/core/actions/EndTurnAction.spec.ts index a69b7d5..9920341 100644 --- a/src/core/actions/EndTurnAction.spec.ts +++ b/src/core/actions/EndTurnAction.spec.ts @@ -1,14 +1,18 @@ module TS.SpaceTac.Specs { describe("EndTurnAction", () => { it("can't be applied to non-playing ship", () => { + spyOn(console, "warn").and.stub(); + var battle = Battle.newQuickRandom(); var action = new EndTurnAction(); - expect(action.canBeUsed(battle, battle.play_order[0])).toBe(true); - expect(action.canBeUsed(battle, battle.play_order[1])).toBe(false); + expect(action.checkCannotBeApplied(battle.play_order[0])).toBe(null); + expect(action.checkCannotBeApplied(battle.play_order[1])).toBe("ship not playing"); - var result = action.apply(battle, battle.play_order[1], null); + var result = action.apply(battle.play_order[1], null); expect(result).toBe(false); + + expect(console.warn).toHaveBeenCalledWith("Action rejected - ship not playing", battle.play_order[1], action, null); }); it("ends turn when applied", () => { @@ -17,7 +21,7 @@ module TS.SpaceTac.Specs { expect(battle.playing_ship_index).toBe(0); - var result = action.apply(battle, battle.play_order[0], null); + var result = action.apply(battle.play_order[0], null); expect(result).toBe(true); expect(battle.playing_ship_index).toBe(1); }); diff --git a/src/core/actions/EndTurnAction.ts b/src/core/actions/EndTurnAction.ts index 6a87162..0ce2f46 100644 --- a/src/core/actions/EndTurnAction.ts +++ b/src/core/actions/EndTurnAction.ts @@ -5,9 +5,13 @@ module TS.SpaceTac { super("endturn", "End ship's turn", false); } - protected customApply(battle: Battle, ship: Ship, target: Target) { + protected customApply(ship: Ship, target: Target) { ship.endTurn(); - battle.advanceToNextShip(); + + let battle = ship.getBattle(); + if (battle) { + battle.advanceToNextShip(); + } } } } diff --git a/src/core/actions/FireWeaponAction.spec.ts b/src/core/actions/FireWeaponAction.spec.ts index 82e4918..177901c 100644 --- a/src/core/actions/FireWeaponAction.spec.ts +++ b/src/core/actions/FireWeaponAction.spec.ts @@ -39,7 +39,7 @@ module TS.SpaceTac { battle.playing_ship = ship; fleet.setBattle(battle); - action.apply(battle, ship, Target.newFromLocation(50, 50)); + action.apply(ship, Target.newFromLocation(50, 50)); expect(mock_apply).toHaveBeenCalledTimes(1); expect(mock_apply).toHaveBeenCalledWith(ship2); }); diff --git a/src/core/actions/FireWeaponAction.ts b/src/core/actions/FireWeaponAction.ts index 19e26f5..1c39189 100644 --- a/src/core/actions/FireWeaponAction.ts +++ b/src/core/actions/FireWeaponAction.ts @@ -12,7 +12,7 @@ module TS.SpaceTac { this.can_target_space = can_target_space; } - checkLocationTarget(battle: Battle, ship: Ship, target: Target): Target { + checkLocationTarget(ship: Ship, target: Target): Target { if (this.can_target_space) { target = target.constraintInRange(ship.arena_x, ship.arena_y, this.equipment.distance); return target; @@ -21,7 +21,7 @@ module TS.SpaceTac { } } - checkShipTarget(battle: Battle, ship: Ship, target: Target): Target { + checkShipTarget(ship: Ship, target: Target): Target { if (ship.getPlayer() === target.ship.getPlayer()) { // No friendly fire return null; @@ -48,7 +48,7 @@ module TS.SpaceTac { return result; } - protected customApply(battle: Battle, ship: Ship, target: Target) { + protected customApply(ship: Ship, target: Target) { // Face the target ship.rotate(Target.newFromShip(ship).getAngleTo(target)); @@ -56,7 +56,7 @@ module TS.SpaceTac { ship.addBattleEvent(new FireEvent(ship, this.equipment, target)); // Apply effects - let effects = this.getEffects(battle, ship, target); + let effects = this.getEffects(ship.getBattle(), ship, target); effects.forEach(([ship, effect]) => effect.applyOnShip(ship)); } } diff --git a/src/core/actions/MoveAction.spec.ts b/src/core/actions/MoveAction.spec.ts index c5a09ee..5cc1563 100644 --- a/src/core/actions/MoveAction.spec.ts +++ b/src/core/actions/MoveAction.spec.ts @@ -15,14 +15,14 @@ module TS.SpaceTac { expect(action.getDistanceByActionPoint(ship)).toBe(0.5); - var result = action.checkTarget(battle, ship, Target.newFromLocation(0, 2)); + var result = action.checkTarget(ship, Target.newFromLocation(0, 2)); expect(result).toEqual(Target.newFromLocation(0, 2)); - result = action.checkTarget(battle, ship, Target.newFromLocation(0, 8)); + result = action.checkTarget(ship, Target.newFromLocation(0, 8)); expect(result).toEqual(Target.newFromLocation(0, 3)); ship.values.power.set(0); - result = action.checkTarget(battle, ship, Target.newFromLocation(0, 8)); + result = action.checkTarget(ship, Target.newFromLocation(0, 8)); expect(result).toBeNull(); }); @@ -31,10 +31,10 @@ module TS.SpaceTac { var ship2 = new Ship(null, "Test2"); var action = new MoveAction(null); - var result = action.checkTarget(null, ship1, Target.newFromShip(ship1)); + var result = action.checkTarget(ship1, Target.newFromShip(ship1)); expect(result).toBeNull(); - result = action.checkTarget(null, ship1, Target.newFromShip(ship2)); + result = action.checkTarget(ship1, Target.newFromShip(ship2)); expect(result).toBeNull(); }); @@ -51,13 +51,15 @@ module TS.SpaceTac { var action = new MoveAction(engine); battle.playing_ship = ship; - var result = action.apply(battle, ship, Target.newFromLocation(10, 10)); + spyOn(console, "warn").and.stub(); + + var result = action.apply(ship, Target.newFromLocation(10, 10)); expect(result).toBe(true); expect(ship.arena_x).toBeCloseTo(3.535533, 0.00001); expect(ship.arena_y).toBeCloseTo(3.535533, 0.00001); expect(ship.values.power.get()).toEqual(0); - result = action.apply(battle, ship, Target.newFromLocation(10, 10)); + result = action.apply(ship, Target.newFromLocation(10, 10)); expect(result).toBe(false); expect(ship.arena_x).toBeCloseTo(3.535533, 0.00001); expect(ship.arena_y).toBeCloseTo(3.535533, 0.00001); @@ -89,19 +91,19 @@ module TS.SpaceTac { var action = new MoveAction(engine); action.safety_distance = 2; - var result = action.checkLocationTarget(battle, ship, Target.newFromLocation(7, 5)); + var result = action.checkLocationTarget(ship, Target.newFromLocation(7, 5)); expect(result).toEqual(Target.newFromLocation(7, 5)); - result = action.checkLocationTarget(battle, ship, Target.newFromLocation(8, 5)); + result = action.checkLocationTarget(ship, Target.newFromLocation(8, 5)); expect(result).toEqual(Target.newFromLocation(8, 5)); - result = action.checkLocationTarget(battle, ship, Target.newFromLocation(9, 5)); + result = action.checkLocationTarget(ship, Target.newFromLocation(9, 5)); expect(result).toEqual(Target.newFromLocation(8, 5)); - result = action.checkLocationTarget(battle, ship, Target.newFromLocation(10, 5)); + result = action.checkLocationTarget(ship, Target.newFromLocation(10, 5)); expect(result).toEqual(Target.newFromLocation(8, 5)); - result = action.checkLocationTarget(battle, ship, Target.newFromLocation(12, 5)); + result = action.checkLocationTarget(ship, Target.newFromLocation(12, 5)); expect(result).toEqual(Target.newFromLocation(12, 5)); }); }); diff --git a/src/core/actions/MoveAction.ts b/src/core/actions/MoveAction.ts index b8a811d..bef4a05 100644 --- a/src/core/actions/MoveAction.ts +++ b/src/core/actions/MoveAction.ts @@ -11,19 +11,24 @@ module TS.SpaceTac { this.safety_distance = 50; } - canBeUsed(battle: Battle, ship: Ship, remaining_ap: number = null): boolean { - if (battle && battle.playing_ship !== ship) { - return false; + checkCannotBeApplied(ship: Ship, remaining_ap: number = null): string | null { + let base = super.checkCannotBeApplied(ship, Infinity); + if (base) { + return base; } // Check AP usage if (remaining_ap === null) { remaining_ap = ship.values.power.get(); } - return remaining_ap > 0.0001; + if (remaining_ap > 0.0001) { + return null + } else { + return "not enough power"; + } } - getActionPointsUsage(battle: Battle, ship: Ship, target: Target): number { + getActionPointsUsage(ship: Ship, target: Target): number { if (target === null) { return 0; } @@ -43,23 +48,26 @@ module TS.SpaceTac { return this.equipment.distance / this.equipment.ap_usage; } - checkLocationTarget(battle: Battle, ship: Ship, target: Target): Target { + checkLocationTarget(ship: Ship, target: Target): Target { // Apply maximal distance var max_distance = this.getRangeRadius(ship); target = target.constraintInRange(ship.arena_x, ship.arena_y, max_distance); // Apply collision prevention - battle.play_order.forEach((iship: Ship) => { - if (iship !== ship) { - target = target.moveOutOfCircle(iship.arena_x, iship.arena_y, this.safety_distance, - ship.arena_x, ship.arena_y); - } - }); + let battle = ship.getBattle(); + if (battle) { + battle.play_order.forEach((iship: Ship) => { + if (iship !== ship) { + target = target.moveOutOfCircle(iship.arena_x, iship.arena_y, this.safety_distance, + ship.arena_x, ship.arena_y); + } + }); + } return target; } - protected customApply(battle: Battle, ship: Ship, target: Target) { + protected customApply(ship: Ship, target: Target) { ship.moveTo(target.x, target.y); } } diff --git a/src/core/ai/AIDuel.ts b/src/core/ai/AIDuel.ts index dfc324c..e1cb6cc 100644 --- a/src/core/ai/AIDuel.ts +++ b/src/core/ai/AIDuel.ts @@ -44,14 +44,15 @@ module TS.SpaceTac { /** * Update the result of a single battle */ - update(winner: AbstractAI | null) { - if (winner) { - if (winner == this.ai1) { + update(winner: number) { + if (winner >= 0) { + if (winner == 0) { this.win1 += 1; + console.log(` => Player 1 wins (${this.ai1})`); } else { this.win2 += 1; + console.log(` => Player 2 wins (${this.ai2})`); } - console.log(` => ${winner.name} wins`); } else { this.draw += 1; console.log(" => draw"); @@ -86,9 +87,9 @@ module TS.SpaceTac { } if (battle.ended && !battle.outcome.draw) { - this.update(battle.outcome.winner == battle.fleets[0] ? this.ai1 : this.ai2); + this.update(battle.fleets.indexOf(battle.outcome.winner)); } else { - this.update(null); + this.update(-1); } if (!this.stopped) { this.scheduled = Timer.global.schedule(100, () => this.next()); diff --git a/src/core/ai/BullyAI.ts b/src/core/ai/BullyAI.ts index b8eb2a5..d9a31bf 100644 --- a/src/core/ai/BullyAI.ts +++ b/src/core/ai/BullyAI.ts @@ -153,7 +153,7 @@ module TS.SpaceTac { if (distance > safety_distance) { // Don't move too close target = target.constraintInRange(this.ship.arena_x, this.ship.arena_y, (distance - safety_distance) * APPROACH_FACTOR); - target = engine.action.checkLocationTarget(this.ship.getBattle(), this.ship, target); + target = engine.action.checkLocationTarget(this.ship, target); return new BullyManeuver(new Maneuver(this.ship, engine, target)); } else { return null; diff --git a/src/core/ai/Maneuver.ts b/src/core/ai/Maneuver.ts index 0a1d8e7..2b7855d 100644 --- a/src/core/ai/Maneuver.ts +++ b/src/core/ai/Maneuver.ts @@ -32,8 +32,8 @@ module TS.SpaceTac { apply(): void { if (this.simulation.success) { this.simulation.parts.forEach(part => { - if (!part.action.apply(this.ship.getBattle(), this.ship, part.target)) { - console.error("AI cannot apply maneuver", this); + if (!part.action.apply(this.ship, part.target)) { + console.error("AI cannot apply maneuver", this, part); } }); } diff --git a/src/core/equipments/AbstractWeapon.spec.ts b/src/core/equipments/AbstractWeapon.spec.ts index fdb5b0f..1ddc88c 100644 --- a/src/core/equipments/AbstractWeapon.spec.ts +++ b/src/core/equipments/AbstractWeapon.spec.ts @@ -38,15 +38,15 @@ module TS.SpaceTac.Specs { weapon.ap_usage = new Range(2); var equipment = weapon.generateFixed(0); - expect(equipment.action.canBeUsed(null, ship)).toBe(true); + expect(equipment.action.checkCannotBeApplied(ship)).toBe(null); weapon.ap_usage = new Range(3); equipment = weapon.generateFixed(0); - expect(equipment.action.canBeUsed(null, ship)).toBe(true); + expect(equipment.action.checkCannotBeApplied(ship)).toBe(null); weapon.ap_usage = new Range(4); equipment = weapon.generateFixed(0); - expect(equipment.action.canBeUsed(null, ship)).toBe(false); + expect(equipment.action.checkCannotBeApplied(ship)).toBe("not enough power"); }); it("can't friendly fire", function () { @@ -60,9 +60,9 @@ module TS.SpaceTac.Specs { weapon.setRange(10, 10); var equipment = weapon.generateFixed(0); - expect(equipment.action.checkShipTarget(null, ship1a, Target.newFromShip(ship2a))).toEqual( + expect(equipment.action.checkShipTarget(ship1a, Target.newFromShip(ship2a))).toEqual( Target.newFromShip(ship2a)); - expect(equipment.action.checkShipTarget(null, ship1a, Target.newFromShip(ship1b))).toBeNull(); + expect(equipment.action.checkShipTarget(ship1a, Target.newFromShip(ship1b))).toBeNull(); }); it("can't fire farther than its range", function () { @@ -78,25 +78,25 @@ module TS.SpaceTac.Specs { var equipment = weapon.generateFixed(0); expect(equipment.distance).toEqual(10); - expect(equipment.action.checkLocationTarget(null, ship, Target.newFromLocation(15, 10))).toEqual( + expect(equipment.action.checkLocationTarget(ship, Target.newFromLocation(15, 10))).toEqual( Target.newFromLocation(15, 10)); - expect(equipment.action.checkLocationTarget(null, ship, Target.newFromLocation(30, 10))).toEqual( + expect(equipment.action.checkLocationTarget(ship, Target.newFromLocation(30, 10))).toEqual( Target.newFromLocation(20, 10)); // Ship targetting var ship2 = new Ship(fleet2); ship2.setArenaPosition(10, 15); - expect(equipment.action.checkShipTarget(null, ship, Target.newFromShip(ship2))).toEqual( + expect(equipment.action.checkShipTarget(ship, Target.newFromShip(ship2))).toEqual( Target.newFromShip(ship2)); ship2.setArenaPosition(10, 25); - expect(equipment.action.checkShipTarget(null, ship, Target.newFromShip(ship2))).toBeNull(); + expect(equipment.action.checkShipTarget(ship, Target.newFromShip(ship2))).toBeNull(); // Forbid targetting in space weapon.setRange(10, 10, false); equipment = weapon.generateFixed(0); - expect(equipment.action.checkLocationTarget(null, ship, Target.newFromLocation(15, 10))).toBeNull(); + expect(equipment.action.checkLocationTarget(ship, Target.newFromLocation(15, 10))).toBeNull(); }); it("can target an enemy ship and damage it", function () { @@ -119,17 +119,17 @@ module TS.SpaceTac.Specs { var equipment = weapon.generateFixed(0); - equipment.action.apply(null, ship1, Target.newFromShip(ship2)); + equipment.action.apply(ship1, Target.newFromShip(ship2)); expect(ship2.values.hull.get()).toEqual(100); expect(ship2.values.shield.get()).toEqual(10); expect(ship1.values.power.get()).toEqual(49); - equipment.action.apply(null, ship1, Target.newFromShip(ship2)); + equipment.action.apply(ship1, Target.newFromShip(ship2)); expect(ship2.values.hull.get()).toEqual(90); expect(ship2.values.shield.get()).toEqual(0); expect(ship1.values.power.get()).toEqual(48); - equipment.action.apply(null, ship1, Target.newFromShip(ship2)); + equipment.action.apply(ship1, Target.newFromShip(ship2)); expect(ship2.values.hull.get()).toEqual(70); expect(ship2.values.shield.get()).toEqual(0); expect(ship1.values.power.get()).toEqual(47); diff --git a/src/core/equipments/PowerDepleter.spec.ts b/src/core/equipments/PowerDepleter.spec.ts index f8dc971..b5757d7 100644 --- a/src/core/equipments/PowerDepleter.spec.ts +++ b/src/core/equipments/PowerDepleter.spec.ts @@ -13,7 +13,7 @@ module TS.SpaceTac.Specs { expect(target.sticky_effects).toEqual([]); // Attribute is immediately limited - equipment.action.apply(null, ship, Target.newFromShip(target)); + equipment.action.apply(ship, Target.newFromShip(target)); expect(target.values.power.get()).toBe(4); expect(target.sticky_effects).toEqual([ diff --git a/src/core/equipments/RepairDrone.spec.ts b/src/core/equipments/RepairDrone.spec.ts index eaa8647..7840dee 100644 --- a/src/core/equipments/RepairDrone.spec.ts +++ b/src/core/equipments/RepairDrone.spec.ts @@ -7,10 +7,10 @@ module TS.SpaceTac.Equipments { expect(equipment.target_effects).toEqual([new ValueEffect("hull", 30)]); let battle = new Battle(); - let ship = new Ship(); + let ship = battle.fleets[0].addShip(); battle.playing_ship = ship; TestTools.setShipAP(ship, 10); - let result = equipment.action.apply(battle, ship, new Target(5, 5, null)); + let result = equipment.action.apply(ship, new Target(5, 5, null)); expect(result).toBe(true); expect(battle.drones.length).toBe(1); diff --git a/src/core/equipments/SubMunitionMissile.spec.ts b/src/core/equipments/SubMunitionMissile.spec.ts index 2a4b2a5..a14ceaa 100644 --- a/src/core/equipments/SubMunitionMissile.spec.ts +++ b/src/core/equipments/SubMunitionMissile.spec.ts @@ -34,12 +34,12 @@ module TS.SpaceTac.Specs { battle.log.addFilter("value"); // Fire at a ship - var t = Target.newFromShip(enemy1); - expect(equipment.action.canBeUsed(battle, ship)).toBe(true); - equipment.action.apply(battle, ship, t); + var target = Target.newFromShip(enemy1); + expect(equipment.action.checkCannotBeApplied(ship)).toBe(null); + equipment.action.apply(ship, target); checkHP(50, 10, 50, 10, 50, 10); expect(battle.log.events.length).toBe(4); - expect(battle.log.events[0]).toEqual(new FireEvent(ship, equipment, t)); + expect(battle.log.events[0]).toEqual(new FireEvent(ship, equipment, target)); expect(battle.log.events[1]).toEqual(new DamageEvent(ship, 0, 20)); expect(battle.log.events[2]).toEqual(new DamageEvent(enemy1, 0, 20)); expect(battle.log.events[3]).toEqual(new DamageEvent(enemy2, 0, 20)); @@ -47,24 +47,24 @@ module TS.SpaceTac.Specs { battle.log.clear(); // Fire in space - t = Target.newFromLocation(2.4, 0); - expect(equipment.action.canBeUsed(battle, ship)).toBe(true); - equipment.action.apply(battle, ship, t); + target = Target.newFromLocation(2.4, 0); + expect(equipment.action.checkCannotBeApplied(ship)).toBe(null); + equipment.action.apply(ship, target); checkHP(50, 10, 40, 0, 40, 0); expect(battle.log.events.length).toBe(3); - expect(battle.log.events[0]).toEqual(new FireEvent(ship, equipment, t)); + expect(battle.log.events[0]).toEqual(new FireEvent(ship, equipment, target)); expect(battle.log.events[1]).toEqual(new DamageEvent(enemy1, 10, 10)); expect(battle.log.events[2]).toEqual(new DamageEvent(enemy2, 10, 10)); battle.log.clear(); // Fire far away - t = Target.newFromLocation(5, 0); - expect(equipment.action.canBeUsed(battle, ship)).toBe(true); - equipment.action.apply(battle, ship, t); + target = Target.newFromLocation(5, 0); + expect(equipment.action.checkCannotBeApplied(ship)).toBe(null); + equipment.action.apply(ship, target); checkHP(50, 10, 40, 0, 40, 0); expect(battle.log.events.length).toBe(1); - expect(battle.log.events[0]).toEqual(new FireEvent(ship, equipment, t)); + expect(battle.log.events[0]).toEqual(new FireEvent(ship, equipment, target)); }); }); } diff --git a/src/ui/battle/ActionIcon.ts b/src/ui/battle/ActionIcon.ts index 2b88a2f..4b3d4d1 100644 --- a/src/ui/battle/ActionIcon.ts +++ b/src/ui/battle/ActionIcon.ts @@ -88,7 +88,7 @@ module TS.SpaceTac.UI { if (!this.bar.interactive) { return; } - if (!this.action.canBeUsed(this.battleview.battle, this.ship)) { + if (this.action.checkCannotBeApplied(this.ship)) { return; } if (this.selected) { @@ -104,7 +104,7 @@ module TS.SpaceTac.UI { this.battleview.arena.range_hint.setPrimary(this.ship, this.action); // Update fading statuses - this.bar.updateSelectedActionPower(this.action.getActionPointsUsage(this.battleview.battle, this.ship, null)); + this.bar.updateSelectedActionPower(this.action.getActionPointsUsage(this.ship, null)); // Set the selected state this.setSelected(true); @@ -127,14 +127,14 @@ module TS.SpaceTac.UI { // Called when a target is hovered // This will check the target against current action and adjust it if needed processHover(target: Target): void { - target = this.action.checkTarget(this.battleview.battle, this.ship, target); + target = this.action.checkTarget(this.ship, target); this.targetting.setTarget(target, false, this.action.getBlastRadius(this.ship)); - this.bar.updateSelectedActionPower(this.action.getActionPointsUsage(this.battleview.battle, this.ship, target)); + this.bar.updateSelectedActionPower(this.action.getActionPointsUsage(this.ship, target)); } // Called when a target is selected processSelection(target: Target): void { - if (this.action.apply(this.battleview.battle, this.ship, target)) { + if (this.action.apply(this.ship, target)) { this.bar.actionEnded(); } } @@ -159,7 +159,7 @@ module TS.SpaceTac.UI { // Update the active status, from the action canBeUsed result updateActiveStatus(force = false): void { var old_active = this.active; - this.active = this.action.canBeUsed(this.battleview.battle, this.ship); + this.active = !this.action.checkCannotBeApplied(this.ship); if (force || (this.active != old_active)) { Animation.setVisibility(this.game, this.layer_active, this.active, 500); this.game.tweens.create(this.layer_icon).to({ alpha: this.active ? 1 : 0.3 }, 500).start(); @@ -170,7 +170,7 @@ module TS.SpaceTac.UI { // Update the fading status, given an hypothetical remaining AP updateFadingStatus(remaining_ap: number): void { var old_fading = this.fading; - this.fading = this.active && !this.action.canBeUsed(this.battleview.battle, this.ship, remaining_ap); + this.fading = this.active && (this.action.checkCannotBeApplied(this.ship, remaining_ap) != null); if (this.fading != old_fading) { Animation.setVisibility(this.game, this.layer_active, this.active && !this.fading, 500); }