1
0
Fork 0

Added fading on actions that will become unavailable (WIP)

This commit is contained in:
Michaël Lemaire 2015-02-26 01:00:00 +01:00
parent 7236afe74b
commit 675a7f80c9
14 changed files with 206 additions and 27 deletions

View file

@ -36,7 +36,7 @@
var queryString = new jasmine.QueryString({
getWindowLocation: function() { return window.location; }
});
if (queryString.getParam('onlytests')) {
if (queryString.getParam('onlytests') || queryString.getParam('spec')) {
document.getElementById("-space-tac").hidden = true;
} else {
new SpaceTac.GameRouter();

View file

@ -21,8 +21,18 @@ module SpaceTac.Game {
// 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): boolean {
return true;
canBeUsed(battle: Battle, ship: Ship, remaining_ap: number = null): boolean {
if (battle && battle.playing_ship !== ship) {
// Ship is not playing
return false;
}
// Check AP usage
if (remaining_ap === null) {
remaining_ap = ship.ap_current.current;
}
var ap_usage = this.equipment ? this.equipment.ap_usage : 0;
return remaining_ap >= ap_usage;
}
// Method to check if a target is applicable for this action

View file

@ -7,10 +7,6 @@ module SpaceTac.Game {
super("endturn", false);
}
canBeUsed(battle: Battle, ship: Ship): boolean {
return battle.playing_ship === ship;
}
protected customApply(battle: Battle, ship: Ship, target: Target): boolean {
battle.advanceToNextShip();
return true;

View file

@ -14,10 +14,6 @@ module SpaceTac.Game {
this.can_target_space = can_target_space;
}
canBeUsed(battle: Battle, ship: Ship): boolean {
return ship.ap_current.current >= this.equipment.ap_usage;
}
checkLocationTarget(battle: Battle, ship: Ship, target: Target): Target {
if (this.can_target_space) {
target = target.constraintInRange(ship.arena_x, ship.arena_y, this.equipment.distance);

View file

@ -7,8 +7,16 @@ module SpaceTac.Game {
super("move", true, equipment);
}
canBeUsed(battle: Battle, ship: Ship): boolean {
return ship.ap_current.current > 0;
canBeUsed(battle: Battle, ship: Ship, remaining_ap: number = null): boolean {
if (battle && battle.playing_ship !== ship) {
return false;
}
// Check AP usage
if (remaining_ap === null) {
remaining_ap = ship.ap_current.current;
}
return remaining_ap > 0.0001;
}
checkLocationTarget(battle: Battle, ship: Ship, target: Target): Target {

View file

@ -199,6 +199,7 @@ module SpaceTac.Game.AI.Specs {
var move = ai.checkBullyMove(ship2, weapon);
expect(move).not.toBeNull();
battle.playing_ship = ai.ship;
battle.log.clear();
ai.applyMove(move);

View file

@ -0,0 +1,33 @@
/// <reference path="../../definitions/jasmine.d.ts"/>
module SpaceTac.Game {
"use strict";
describe("BaseAction", function () {
it("check if equipment can be used with remaining AP", function () {
var equipment = new Equipment(SlotType.Armor);
equipment.ap_usage = 3;
var action = new BaseAction("test", false, equipment);
var ship = new Ship();
ship.addSlot(SlotType.Armor).attach(equipment);
ship.ap_current.setMaximal(10);
expect(action.canBeUsed(null, ship)).toBe(false);
ship.ap_current.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);
ship.ap_current.set(3);
expect(action.canBeUsed(null, ship)).toBe(true);
ship.ap_current.set(2);
expect(action.canBeUsed(null, ship)).toBe(false);
});
});
}

View file

@ -49,6 +49,7 @@ module SpaceTac.Game {
engine.distance = 1;
engine.ap_usage = 1;
var action = new MoveAction(engine);
battle.playing_ship = ship;
var result = action.apply(battle, ship, Target.newFromLocation(10, 10));
expect(result).toBe(true);

View file

@ -22,6 +22,7 @@ module SpaceTac.View {
this.loadImage("battle/actionbar.png");
this.loadImage("battle/action-inactive.png");
this.loadImage("battle/action-active.png");
this.loadImage("battle/action-fading.png");
this.loadImage("battle/actionpointsempty.png");
this.loadImage("battle/actionpointsfull.png");
this.loadImage("battle/arena/shipspritehover.png");

View file

@ -60,6 +60,19 @@ module SpaceTac.View {
}
}
// Update fading flags
// ap_usage is the consumption of currently selected action
updateFadings(ap_usage: number): void {
var remaining_ap = this.ship.ap_current.current - ap_usage;
if (remaining_ap < 0) {
remaining_ap = 0;
}
this.actions.forEach((icon: ActionIcon) => {
icon.updateFadingStatus(remaining_ap);
});
}
// Set action icons from selected ship
setShip(ship: Game.Ship): void {
var action_bar = this;

View file

@ -15,6 +15,12 @@ module SpaceTac.View {
// Related game action
action: Game.BaseAction;
// True if the action can be used
active: boolean;
// True if an action is currently selected, and this one won't be available after its use
fading: boolean;
// Current targetting
private targetting: Targetting;
@ -24,6 +30,9 @@ module SpaceTac.View {
// Layer applied when the action is active
private layer_active: Phaser.Image;
// Layer applied when the action will become unavailable if another action is played
private layer_fading: Phaser.Image;
// Create an icon for a single ship action
constructor(bar: ActionBar, x: number, y: number, ship: Game.Ship, action: Game.BaseAction) {
this.bar = bar;
@ -35,13 +44,21 @@ module SpaceTac.View {
bar.addChild(this);
// Active layer
this.active = false;
this.layer_active = new Phaser.Image(this.game, 0, 0, "battle-action-active", 0);
this.layer_active.visible = false;
this.addChild(this.layer_active);
// Icon layer
this.layer_icon = new Phaser.Image(this.game, 15, 18, "battle-actions-" + action.code, 0);
this.addChild(this.layer_icon);
// Fading layer
this.fading = false;
this.layer_fading = new Phaser.Image(this.game, 0, 0, "battle-action-fading", 0);
this.layer_fading.visible = false;
this.addChild(this.layer_fading);
// Click process
this.onInputUp.add(() => {
this.processClick();
@ -62,8 +79,14 @@ module SpaceTac.View {
// End any previously selected action
this.bar.actionEnded();
// Update fading statuses
this.bar.updateFadings(this.action.equipment.ap_usage);
// Set the lighting color to highlight
this.layer_active.tint = 0xFFD060;
if (this.game.renderType !== Phaser.HEADLESS) {
// Tint doesn't work in headless renderer
this.layer_active.tint = 0xFFD060;
}
if (this.action.needs_target) {
// Switch to targetting mode (will apply action when a target is selected)
@ -104,10 +127,16 @@ module SpaceTac.View {
// Update the active status, from the action canBeUsed result
updateActiveStatus(): void {
var active = this.action.canBeUsed(this.battleview.battle, this.ship);
Animation.setVisibility(this.game, this.layer_active, active, 500);
this.game.tweens.create(this.layer_icon).to({alpha: active ? 1 : 0.3}, 500).start();
this.input.useHandCursor = active;
this.active = this.action.canBeUsed(this.battleview.battle, this.ship);
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();
this.input.useHandCursor = this.active;
}
// Update the fading status, given an hypothetical remaining AP
updateFadingStatus(remaining_ap: number): void {
this.fading = !this.action.canBeUsed(this.battleview.battle, this.ship, remaining_ap);
Animation.setVisibility(this.game, this.layer_fading, this.fading, 200);
}
}
}

View file

@ -0,0 +1,87 @@
/// <reference path="../../definitions/jasmine.d.ts"/>
/// <reference path="TestGame.ts"/>
module SpaceTac.View.Specs {
"use strict";
describe("ActionBar", () => {
inbattleview_it("lists available actions for selected ship", (battleview: BattleView) => {
var bar = battleview.action_bar;
// Ship not owned by current battleview player
var ship = new Game.Ship();
bar.setShip(ship);
expect(bar.actions.length).toBe(0);
// Ship with no equipment (only endturn action)
battleview.player = ship.getPlayer();
bar.setShip(ship);
expect(bar.actions.length).toBe(1);
expect(bar.actions[0].action.code).toEqual("endturn");
// Add an engine, with move action
ship.addSlot(Game.SlotType.Engine).attach((new Game.Equipments.ConventionalEngine()).generate());
bar.setShip(ship);
expect(bar.actions.length).toBe(2);
expect(bar.actions[0].action.code).toEqual("move");
// Add a weapon, with fire action
ship.addSlot(Game.SlotType.Weapon).attach((new Game.Equipments.GatlingGun()).generate());
bar.setShip(ship);
expect(bar.actions.length).toBe(3);
expect(bar.actions[1].action.code).toEqual("fire-gatlinggun");
});
inbattleview_it("mark actions that would become unavailable after use", (battleview: BattleView) => {
var bar = battleview.action_bar;
var ship = new Game.Ship();
var engine = (new Game.Equipments.ConventionalEngine()).generate();
engine.ap_usage = 8;
engine.distance = 4;
ship.addSlot(Game.SlotType.Engine).attach(engine);
var weapon1 = (new Game.Equipments.GatlingGun()).generate();
weapon1.ap_usage = 3;
ship.addSlot(Game.SlotType.Weapon).attach(weapon1);
var weapon2 = (new Game.Equipments.GatlingGun()).generate();
weapon2.ap_usage = 5;
ship.addSlot(Game.SlotType.Weapon).attach(weapon2);
battleview.battle.playing_ship = ship;
battleview.player = ship.getPlayer();
ship.ap_current.setMaximal(10);
ship.ap_current.set(9);
bar.setShip(ship);
expect(bar.actions.length).toBe(4);
var checkFading = (fading: number[], available: number[]) => {
fading.forEach((index: number) => {
var icon = bar.actions[index];
expect(icon.fading).toBe(true);
});
available.forEach((index: number) => {
var icon = bar.actions[index];
expect(icon.fading).toBe(false);
});
};
// Weapon 1 leaves all choices open
bar.actions[1].processClick();
checkFading([], [0, 1, 2, 3]);
// Weapon 2 can't be fired twice
bar.actions[2].processClick();
checkFading([2], [0, 1, 3]);
// Not enough AP for both weapons
ship.ap_current.set(7);
bar.actions[2].processClick();
checkFading([1, 2], [0, 3]);
// Not enough AP to move
ship.ap_current.set(3);
bar.actions[1].processClick();
checkFading([0, 1, 2], [3]);
});
});
}

View file

@ -5,15 +5,6 @@
module SpaceTac.View.Specs {
"use strict";
export function inbattleview_it(desc: string, func: (battleview: BattleView) => void) {
var battleview = new BattleView();
var battle = Game.Battle.newQuickRandom();
var player = battle.playing_ship.getPlayer();
ingame_it(desc, (game: Phaser.Game, state: Phaser.State) => {
func(battleview);
}, battleview, player, battle);
}
describe("BattleView", () => {
inbattleview_it("forwards events in targetting mode", (battleview: BattleView) => {
expect(battleview.targetting).toBeNull();

View file

@ -7,6 +7,9 @@ module SpaceTac.View.Specs {
export function ingame_it(desc: string, func: (game: Phaser.Game, state: Phaser.State) => void,
state: Phaser.State = null, ...stateargs: any[]) {
it(desc, (done: () => void) => {
spyOn(console, "log").and.stub();
spyOn(console, "warn").and.stub();
var game = new Phaser.Game(500, 500, Phaser.HEADLESS);
if (!state) {
@ -31,4 +34,14 @@ module SpaceTac.View.Specs {
game.state.start.apply(game.state, args);
});
}
// Test game wrapper, with a battleview initialized on a random battle
export function inbattleview_it(desc: string, func: (battleview: BattleView) => void) {
var battleview = new BattleView();
var battle = Game.Battle.newQuickRandom();
var player = battle.playing_ship.getPlayer();
ingame_it(desc, (game: Phaser.Game, state: Phaser.State) => {
func(battleview);
}, battleview, player, battle);
}
}