Removed dead ships from play order
This commit is contained in:
parent
939313889c
commit
4b2d46754f
2
TODO.md
2
TODO.md
|
@ -41,7 +41,6 @@ Battle
|
||||||
* Fix arena's ship hovering happening even when the character sheet is open on top
|
* Fix arena's ship hovering happening even when the character sheet is open on top
|
||||||
* Add a voluntary retreat option
|
* Add a voluntary retreat option
|
||||||
* Add scroll buttons when there are too many actions
|
* Add scroll buttons when there are too many actions
|
||||||
* Remove dead ships from ship list and play order
|
|
||||||
* Add quick animation of playing ship indicator, on ship change
|
* Add quick animation of playing ship indicator, on ship change
|
||||||
* Toggle bar/text display in power section of action bar
|
* Toggle bar/text display in power section of action bar
|
||||||
* Display effects description instead of attribute changes
|
* Display effects description instead of attribute changes
|
||||||
|
@ -64,6 +63,7 @@ Battle
|
||||||
* Add shorcut to perform only the "move" part of a move+fire simulation
|
* Add shorcut to perform only the "move" part of a move+fire simulation
|
||||||
* Fix delay of shield/hull impact effects (should depend on weapon animation, and ship location)
|
* Fix delay of shield/hull impact effects (should depend on weapon animation, and ship location)
|
||||||
* Indicate visually the power gain of "end turn"
|
* Indicate visually the power gain of "end turn"
|
||||||
|
* Add a turn count marker in the ship list
|
||||||
|
|
||||||
Ships models and equipments
|
Ships models and equipments
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit a530998523e8f8c7a37323d5dc047241f71f6a36
|
Subproject commit 586788a4685a5b9a5cc8f4882f48f18c91997dc3
|
|
@ -63,54 +63,44 @@ module TK.SpaceTac {
|
||||||
var fleet1 = new Fleet();
|
var fleet1 = new Fleet();
|
||||||
var fleet2 = new Fleet();
|
var fleet2 = new Fleet();
|
||||||
|
|
||||||
var ship1 = new Ship(fleet1, "F1S1");
|
var ship1 = new Ship(fleet1, "ship1");
|
||||||
var ship2 = new Ship(fleet1, "F1S2");
|
var ship2 = new Ship(fleet1, "ship2");
|
||||||
var ship3 = new Ship(fleet2, "F2S1");
|
var ship3 = new Ship(fleet2, "ship3");
|
||||||
|
|
||||||
var battle = new Battle(fleet1, fleet2);
|
var battle = new Battle(fleet1, fleet2);
|
||||||
|
|
||||||
// Check empty play_order case
|
// Check empty play_order case
|
||||||
expect(battle.playing_ship).toBeNull();
|
expect(battle.playing_ship).toBeNull();
|
||||||
expect(battle.playing_ship_index).toBeNull();
|
|
||||||
battle.advanceToNextShip();
|
battle.advanceToNextShip();
|
||||||
expect(battle.playing_ship).toBeNull();
|
expect(battle.playing_ship).toBeNull();
|
||||||
expect(battle.playing_ship_index).toBeNull();
|
|
||||||
|
|
||||||
// Force play order
|
// Force play order
|
||||||
iforeach(battle.iships(), ship => ship.setAttribute("maneuvrability", 1));
|
iforeach(battle.iships(), ship => ship.setAttribute("maneuvrability", 1));
|
||||||
var gen = new SkewedRandomGenerator([0.1, 0.2, 0.0]);
|
var gen = new SkewedRandomGenerator([0.1, 0.2, 0.0]);
|
||||||
battle.throwInitiative(gen);
|
battle.throwInitiative(gen);
|
||||||
|
|
||||||
expect(battle.playing_ship).toBeNull();
|
expect(battle.playing_ship).toBeNull();
|
||||||
expect(battle.playing_ship_index).toBeNull();
|
|
||||||
|
|
||||||
battle.advanceToNextShip();
|
battle.advanceToNextShip();
|
||||||
|
|
||||||
expect(battle.playing_ship).toBe(ship2);
|
expect(battle.playing_ship).toBe(ship2);
|
||||||
expect(battle.playing_ship_index).toBe(0);
|
|
||||||
|
|
||||||
battle.advanceToNextShip();
|
battle.advanceToNextShip();
|
||||||
|
|
||||||
expect(battle.playing_ship).toBe(ship1);
|
expect(battle.playing_ship).toBe(ship1);
|
||||||
expect(battle.playing_ship_index).toBe(1);
|
|
||||||
|
|
||||||
battle.advanceToNextShip();
|
battle.advanceToNextShip();
|
||||||
|
|
||||||
expect(battle.playing_ship).toBe(ship3);
|
expect(battle.playing_ship).toBe(ship3);
|
||||||
expect(battle.playing_ship_index).toBe(2);
|
|
||||||
|
|
||||||
battle.advanceToNextShip();
|
battle.advanceToNextShip();
|
||||||
|
|
||||||
expect(battle.playing_ship).toBe(ship2);
|
expect(battle.playing_ship).toBe(ship2);
|
||||||
expect(battle.playing_ship_index).toBe(0);
|
|
||||||
|
|
||||||
// A dead ship is not skipped
|
// A dead ship is skipped
|
||||||
ship1.setDead();
|
ship1.setDead();
|
||||||
|
|
||||||
battle.advanceToNextShip();
|
battle.advanceToNextShip();
|
||||||
|
expect(battle.playing_ship).toBe(ship3);
|
||||||
|
|
||||||
expect(battle.playing_ship).toBe(ship1);
|
// Playing ship dies
|
||||||
expect(battle.playing_ship_index).toBe(1);
|
ship3.setDead();
|
||||||
|
battle.advanceToNextShip();
|
||||||
|
expect(battle.playing_ship).toBe(ship2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("calls startTurn on ships", function () {
|
it("calls startTurn on ships", function () {
|
||||||
|
@ -290,7 +280,7 @@ module TK.SpaceTac {
|
||||||
expect(battle.canPlay(player)).toBe(false);
|
expect(battle.canPlay(player)).toBe(false);
|
||||||
|
|
||||||
let ship = new Ship();
|
let ship = new Ship();
|
||||||
battle.playing_ship = ship;
|
TestTools.setShipPlaying(battle, ship);
|
||||||
|
|
||||||
expect(battle.canPlay(player)).toBe(false);
|
expect(battle.canPlay(player)).toBe(false);
|
||||||
|
|
||||||
|
@ -306,28 +296,28 @@ module TK.SpaceTac {
|
||||||
battle.advanceToNextShip();
|
battle.advanceToNextShip();
|
||||||
|
|
||||||
expect(battle.playing_ship).toBe(battle.play_order[0]);
|
expect(battle.playing_ship).toBe(battle.play_order[0]);
|
||||||
expect(battle.getTurnsBefore(battle.play_order[0])).toBe(0);
|
expect(battle.getPlayOrder(battle.play_order[0])).toBe(0);
|
||||||
expect(battle.getTurnsBefore(battle.play_order[1])).toBe(1);
|
expect(battle.getPlayOrder(battle.play_order[1])).toBe(1);
|
||||||
expect(battle.getTurnsBefore(battle.play_order[2])).toBe(2);
|
expect(battle.getPlayOrder(battle.play_order[2])).toBe(2);
|
||||||
|
|
||||||
battle.advanceToNextShip();
|
battle.advanceToNextShip();
|
||||||
|
|
||||||
expect(battle.playing_ship).toBe(battle.play_order[1]);
|
expect(battle.playing_ship).toBe(battle.play_order[1]);
|
||||||
expect(battle.getTurnsBefore(battle.play_order[0])).toBe(2);
|
expect(battle.getPlayOrder(battle.play_order[0])).toBe(2);
|
||||||
expect(battle.getTurnsBefore(battle.play_order[1])).toBe(0);
|
expect(battle.getPlayOrder(battle.play_order[1])).toBe(0);
|
||||||
expect(battle.getTurnsBefore(battle.play_order[2])).toBe(1);
|
expect(battle.getPlayOrder(battle.play_order[2])).toBe(1);
|
||||||
|
|
||||||
battle.advanceToNextShip();
|
battle.advanceToNextShip();
|
||||||
|
|
||||||
expect(battle.getTurnsBefore(battle.play_order[0])).toBe(1);
|
expect(battle.getPlayOrder(battle.play_order[0])).toBe(1);
|
||||||
expect(battle.getTurnsBefore(battle.play_order[1])).toBe(2);
|
expect(battle.getPlayOrder(battle.play_order[1])).toBe(2);
|
||||||
expect(battle.getTurnsBefore(battle.play_order[2])).toBe(0);
|
expect(battle.getPlayOrder(battle.play_order[2])).toBe(0);
|
||||||
|
|
||||||
battle.advanceToNextShip();
|
battle.advanceToNextShip();
|
||||||
|
|
||||||
expect(battle.getTurnsBefore(battle.play_order[0])).toBe(0);
|
expect(battle.getPlayOrder(battle.play_order[0])).toBe(0);
|
||||||
expect(battle.getTurnsBefore(battle.play_order[1])).toBe(1);
|
expect(battle.getPlayOrder(battle.play_order[1])).toBe(1);
|
||||||
expect(battle.getTurnsBefore(battle.play_order[2])).toBe(2);
|
expect(battle.getPlayOrder(battle.play_order[2])).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("lists area effects", function () {
|
it("lists area effects", function () {
|
||||||
|
|
|
@ -19,15 +19,15 @@ module TK.SpaceTac {
|
||||||
// List of fleets engaged in battle
|
// List of fleets engaged in battle
|
||||||
fleets: Fleet[]
|
fleets: Fleet[]
|
||||||
|
|
||||||
// List of ships, sorted by their initiative throw
|
// Container of all engaged ships
|
||||||
|
ships: RObjectContainer<Ship>
|
||||||
|
|
||||||
|
// List of playing ships, sorted by their initiative throw
|
||||||
play_order: Ship[]
|
play_order: Ship[]
|
||||||
|
play_index = -1
|
||||||
|
|
||||||
// Current turn
|
// Current battle "cycle" (one cycle is one turn done for all ships in the play order)
|
||||||
turn: number
|
cycle: number
|
||||||
|
|
||||||
// Current ship whose turn it is to play
|
|
||||||
playing_ship_index: number | null
|
|
||||||
playing_ship: Ship | null
|
|
||||||
|
|
||||||
// List of deployed drones
|
// List of deployed drones
|
||||||
drones: Drone[] = []
|
drones: Drone[] = []
|
||||||
|
@ -47,9 +47,8 @@ module TK.SpaceTac {
|
||||||
// Create a battle between two fleets
|
// Create a battle between two fleets
|
||||||
constructor(fleet1 = new Fleet(), fleet2 = new Fleet(), width = 1808, height = 948) {
|
constructor(fleet1 = new Fleet(), fleet2 = new Fleet(), width = 1808, height = 948) {
|
||||||
this.fleets = [fleet1, fleet2];
|
this.fleets = [fleet1, fleet2];
|
||||||
|
this.ships = new RObjectContainer(fleet1.ships.concat(fleet2.ships));
|
||||||
this.play_order = [];
|
this.play_order = [];
|
||||||
this.playing_ship_index = null;
|
|
||||||
this.playing_ship = null;
|
|
||||||
this.ended = false;
|
this.ended = false;
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
|
@ -82,21 +81,17 @@ module TK.SpaceTac {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the number of turns in a game cycle.
|
* Get the currently playing ship
|
||||||
*/
|
*/
|
||||||
getCycleLength(): number {
|
get playing_ship(): Ship | null {
|
||||||
return this.play_order.length;
|
return this.play_order[this.play_index] || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the number of turns before a specific ship plays (currently playing ship will return 0).
|
* Get a ship by its ID.
|
||||||
*/
|
*/
|
||||||
getTurnsBefore(ship: Ship): number {
|
getShip(id: RObjectId): Ship | null {
|
||||||
let pos = this.play_order.indexOf(ship) - (this.playing_ship_index || 0);
|
return this.ships.get(id);
|
||||||
if (pos < 0) {
|
|
||||||
pos += this.play_order.length;
|
|
||||||
}
|
|
||||||
return pos;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -150,6 +145,42 @@ module TK.SpaceTac {
|
||||||
return (ship2.play_priority - ship1.play_priority);
|
return (ship2.play_priority - ship1.play_priority);
|
||||||
});
|
});
|
||||||
this.play_order = play_order;
|
this.play_order = play_order;
|
||||||
|
this.play_index = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of turns before a specific ship plays (currently playing ship will return 0).
|
||||||
|
*
|
||||||
|
* Returns -1 if the ship is not in the play list.
|
||||||
|
*/
|
||||||
|
getPlayOrder(ship: Ship): number {
|
||||||
|
let index = this.play_order.indexOf(ship);
|
||||||
|
if (index < 0) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
let result = index - this.play_index;
|
||||||
|
return (result < 0) ? result + this.play_order.length : result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a ship in the play order list
|
||||||
|
*/
|
||||||
|
removeFromPlayOrder(idx: number): void {
|
||||||
|
this.play_order.splice(idx, 1);
|
||||||
|
if (idx <= this.play_index) {
|
||||||
|
this.play_index -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a ship from the play order list
|
||||||
|
*/
|
||||||
|
insertInPlayOrder(idx: number, ship: Ship): void {
|
||||||
|
this.play_order.splice(idx, 0, ship);
|
||||||
|
if (idx <= this.play_index) {
|
||||||
|
this.play_index += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Defines the initial ship positions of all engaged fleets
|
// Defines the initial ship positions of all engaged fleets
|
||||||
|
@ -195,7 +226,7 @@ module TK.SpaceTac {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply to all ships
|
// Apply to all ships
|
||||||
iforeach(this.iships(), ship => ship.endBattle(this.turn));
|
iforeach(this.iships(), ship => ship.endBattle(this.cycle));
|
||||||
this.stats.onBattleEnd(this.fleets[0], this.fleets[1]);
|
this.stats.onBattleEnd(this.fleets[0], this.fleets[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,10 +259,10 @@ module TK.SpaceTac {
|
||||||
// If at the end of the play order, next turn will start automatically
|
// If at the end of the play order, next turn will start automatically
|
||||||
// Member 'play_order' must be defined before calling this function
|
// Member 'play_order' must be defined before calling this function
|
||||||
advanceToNextShip(log: boolean = true): void {
|
advanceToNextShip(log: boolean = true): void {
|
||||||
var previous_ship = this.playing_ship;
|
let previous_ship = this.playing_ship;
|
||||||
|
|
||||||
if (this.playing_ship && this.playing_ship.playing) {
|
if (previous_ship && previous_ship.playing) {
|
||||||
this.playing_ship.endTurn();
|
previous_ship.endTurn();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.checkEndBattle(log)) {
|
if (this.checkEndBattle(log)) {
|
||||||
|
@ -240,21 +271,14 @@ module TK.SpaceTac {
|
||||||
|
|
||||||
this.drones.forEach(drone => drone.activate());
|
this.drones.forEach(drone => drone.activate());
|
||||||
|
|
||||||
if (this.play_order.length === 0) {
|
this.play_index += 1;
|
||||||
this.playing_ship_index = null;
|
if (this.play_index >= this.play_order.length) {
|
||||||
this.playing_ship = null;
|
this.play_index = 0;
|
||||||
} else {
|
|
||||||
if (this.playing_ship_index == null) {
|
|
||||||
this.playing_ship_index = 0;
|
|
||||||
} else {
|
|
||||||
this.playing_ship_index = (this.playing_ship_index + 1) % this.play_order.length;
|
|
||||||
}
|
|
||||||
this.playing_ship = this.play_order[this.playing_ship_index];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.playing_ship) {
|
if (this.playing_ship) {
|
||||||
if (this.playing_ship_index == 0) {
|
if (this.play_index == 0) {
|
||||||
this.turn += 1;
|
this.cycle += 1;
|
||||||
}
|
}
|
||||||
this.playing_ship.startTurn();
|
this.playing_ship.startTurn();
|
||||||
}
|
}
|
||||||
|
@ -288,7 +312,7 @@ module TK.SpaceTac {
|
||||||
// This will not add any event to the battle log
|
// This will not add any event to the battle log
|
||||||
start(): void {
|
start(): void {
|
||||||
this.ended = false;
|
this.ended = false;
|
||||||
this.turn = 0;
|
this.cycle = 0;
|
||||||
this.placeShips();
|
this.placeShips();
|
||||||
this.stats.onBattleStart(this.fleets[0], this.fleets[1]);
|
this.stats.onBattleStart(this.fleets[0], this.fleets[1]);
|
||||||
this.throwInitiative();
|
this.throwInitiative();
|
||||||
|
@ -324,7 +348,7 @@ module TK.SpaceTac {
|
||||||
// Indicate emergency stasis
|
// Indicate emergency stasis
|
||||||
this.play_order.forEach(ship => {
|
this.play_order.forEach(ship => {
|
||||||
if (!ship.alive) {
|
if (!ship.alive) {
|
||||||
let event = new DeathEvent(ship);
|
let event = new DeathEvent(this, ship);
|
||||||
event.initial = true;
|
event.initial = true;
|
||||||
result.push(event);
|
result.push(event);
|
||||||
}
|
}
|
||||||
|
@ -347,6 +371,18 @@ module TK.SpaceTac {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a list of events on this game state (and optionally store the events in the battle log)
|
||||||
|
*/
|
||||||
|
applyEvents(events: BaseBattleEvent[], log = true): void {
|
||||||
|
events.forEach(event => {
|
||||||
|
event.apply(this);
|
||||||
|
if (log) {
|
||||||
|
this.log.add(event);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the initial ship positions for one fleet
|
* Defines the initial ship positions for one fleet
|
||||||
*
|
*
|
||||||
|
|
|
@ -22,12 +22,13 @@ module TK.SpaceTac.Specs {
|
||||||
|
|
||||||
it("adds an equipment", function () {
|
it("adds an equipment", function () {
|
||||||
let battle = new Battle();
|
let battle = new Battle();
|
||||||
battle.playing_ship = new Ship();
|
let ship = new Ship();
|
||||||
battle.playing_ship.upgradeSkill("skill_materials");
|
TestTools.setShipPlaying(battle, ship);
|
||||||
|
ship.upgradeSkill("skill_materials");
|
||||||
|
|
||||||
expect(battle.playing_ship.listEquipment()).toEqual([]);
|
expect(ship.listEquipment()).toEqual([]);
|
||||||
battle.cheats.equip("Iron Hull");
|
battle.cheats.equip("Iron Hull");
|
||||||
expect(battle.playing_ship.listEquipment()).toEqual([<any>jasmine.objectContaining({name: "Iron Hull", level: 1})]);
|
expect(ship.listEquipment()).toEqual([<any>jasmine.objectContaining({ name: "Iron Hull", level: 1 })]);
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,7 +83,8 @@ module TK.SpaceTac {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("checks if a fleet is alive", function () {
|
it("checks if a fleet is alive", function () {
|
||||||
let fleet = new Fleet();
|
let battle = new Battle();
|
||||||
|
let fleet = battle.fleets[0];
|
||||||
expect(fleet.isAlive()).toBe(false);
|
expect(fleet.isAlive()).toBe(false);
|
||||||
|
|
||||||
let ship1 = fleet.addShip();
|
let ship1 = fleet.addShip();
|
||||||
|
|
|
@ -61,6 +61,9 @@ module TK.SpaceTac {
|
||||||
}
|
}
|
||||||
add(this.ships, ship);
|
add(this.ships, ship);
|
||||||
ship.fleet = this;
|
ship.fleet = this;
|
||||||
|
if (this.battle) {
|
||||||
|
this.battle.ships.add(ship);
|
||||||
|
}
|
||||||
return ship;
|
return ship;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -236,7 +236,7 @@ module TK.SpaceTac.Specs {
|
||||||
expect(action.activated).toBe(false);
|
expect(action.activated).toBe(false);
|
||||||
|
|
||||||
let battle = new Battle(ship.fleet);
|
let battle = new Battle(ship.fleet);
|
||||||
battle.playing_ship = ship;
|
TestTools.setShipPlaying(battle, ship);
|
||||||
|
|
||||||
ship.startTurn();
|
ship.startTurn();
|
||||||
expect(action.activated).toBe(false);
|
expect(action.activated).toBe(false);
|
||||||
|
@ -273,7 +273,7 @@ module TK.SpaceTac.Specs {
|
||||||
|
|
||||||
let shield = ship1.addSlot(SlotType.Shield).attach(new Equipment(SlotType.Shield));
|
let shield = ship1.addSlot(SlotType.Shield).attach(new Equipment(SlotType.Shield));
|
||||||
shield.action = new ToggleAction(shield, 0, 15, [new AttributeEffect("shield_capacity", 5)]);
|
shield.action = new ToggleAction(shield, 0, 15, [new AttributeEffect("shield_capacity", 5)]);
|
||||||
battle.playing_ship = ship1;
|
TestTools.setShipPlaying(battle, ship1);
|
||||||
shield.action.apply(ship1);
|
shield.action.apply(ship1);
|
||||||
|
|
||||||
expect(ship1.getAttribute("shield_capacity")).toBe(5);
|
expect(ship1.getAttribute("shield_capacity")).toBe(5);
|
||||||
|
@ -325,15 +325,15 @@ module TK.SpaceTac.Specs {
|
||||||
ship.addDamage(5, 0);
|
ship.addDamage(5, 0);
|
||||||
|
|
||||||
expect(ship.alive).toBe(false);
|
expect(ship.alive).toBe(false);
|
||||||
expect(battle.log.events.length).toBe(4);
|
expect(battle.log.events.length).toBe(3);
|
||||||
expect(battle.log.events[0].code).toEqual("value");
|
expect(battle.log.events[0].code).toEqual("value");
|
||||||
expect(battle.log.events[1].code).toEqual("damage");
|
expect(battle.log.events[1].code).toEqual("damage");
|
||||||
expect(battle.log.events[2].code).toEqual("activeeffects");
|
expect(battle.log.events[2].code).toEqual("death");
|
||||||
expect(battle.log.events[3].code).toEqual("death");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("checks if a ship is able to play", function () {
|
it("checks if a ship is able to play", function () {
|
||||||
var ship = new Ship();
|
let battle = new Battle();
|
||||||
|
let ship = battle.fleets[0].addShip();
|
||||||
|
|
||||||
expect(ship.isAbleToPlay()).toBe(false);
|
expect(ship.isAbleToPlay()).toBe(false);
|
||||||
expect(ship.isAbleToPlay(false)).toBe(true);
|
expect(ship.isAbleToPlay(false)).toBe(true);
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
|
/// <reference path="../common/RObject.ts" />
|
||||||
|
|
||||||
module TK.SpaceTac {
|
module TK.SpaceTac {
|
||||||
/**
|
/**
|
||||||
* A single ship in a fleet
|
* A single ship in a fleet
|
||||||
*/
|
*/
|
||||||
export class Ship {
|
export class Ship extends RObject {
|
||||||
// Fleet this ship is a member of
|
// Fleet this ship is a member of
|
||||||
fleet: Fleet
|
fleet: Fleet
|
||||||
|
|
||||||
|
@ -56,6 +58,8 @@ module TK.SpaceTac {
|
||||||
|
|
||||||
// Create a new ship inside a fleet
|
// Create a new ship inside a fleet
|
||||||
constructor(fleet: Fleet | null = null, name = "unnamed", model = new ShipModel("default", "Default", 1, 0, false, 0)) {
|
constructor(fleet: Fleet | null = null, name = "unnamed", model = new ShipModel("default", "Default", 1, 0, false, 0)) {
|
||||||
|
super();
|
||||||
|
|
||||||
this.fleet = fleet || new Fleet();
|
this.fleet = fleet || new Fleet();
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.alive = true;
|
this.alive = true;
|
||||||
|
@ -463,20 +467,49 @@ module TK.SpaceTac {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the events needed to apply changes to ship values or attributes
|
||||||
|
*/
|
||||||
|
getValueEvents(name: keyof ShipValues, value: number): BaseBattleEvent[] {
|
||||||
|
let result: BaseBattleEvent[] = [];
|
||||||
|
|
||||||
|
let current = this.values[name];
|
||||||
|
if (current.get() != value) {
|
||||||
|
let newval = copy(current);
|
||||||
|
newval.set(value);
|
||||||
|
result.push(new ValueChangeEvent(this, newval, value - current.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produce events to set the ship in emergency stasis
|
||||||
|
*/
|
||||||
|
getDeathEvents(battle: Battle): BaseBattleEvent[] {
|
||||||
|
let result: BaseBattleEvent[] = [];
|
||||||
|
|
||||||
|
keys(SHIP_VALUES).forEach(value => {
|
||||||
|
result = result.concat(this.getValueEvents(value, 0));
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO Remove sticky effects
|
||||||
|
|
||||||
|
result.push(new DeathEvent(battle, this));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the death status on this ship
|
* Set the death status on this ship
|
||||||
*/
|
*/
|
||||||
setDead(log: boolean = true): void {
|
setDead(): void {
|
||||||
this.alive = false;
|
let battle = this.getBattle();
|
||||||
this.values.hull.set(0);
|
if (battle) {
|
||||||
this.values.shield.set(0);
|
let events = this.getDeathEvents(battle);
|
||||||
this.values.power.set(0);
|
battle.applyEvents(events);
|
||||||
|
} else {
|
||||||
this.sticky_effects = [];
|
console.error("Cannot set ship dead outside of battle", this);
|
||||||
this.setActiveEffectsChanged();
|
|
||||||
|
|
||||||
if (log) {
|
|
||||||
this.addBattleEvent(new DeathEvent(this));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -500,7 +533,7 @@ module TK.SpaceTac {
|
||||||
|
|
||||||
if (this.values.hull.get() === 0) {
|
if (this.values.hull.get() === 0) {
|
||||||
// Ship is dead
|
// Ship is dead
|
||||||
this.setDead(log);
|
this.setDead();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,13 @@ module TK.SpaceTac {
|
||||||
return equipment;
|
return equipment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the current playing ship
|
||||||
|
static setShipPlaying(battle: Battle, ship: Ship): void {
|
||||||
|
add(battle.play_order, ship);
|
||||||
|
battle.play_index = battle.play_order.indexOf(ship);
|
||||||
|
ship.playing = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Set a ship action points, adding/updating an equipment if needed
|
// Set a ship action points, adding/updating an equipment if needed
|
||||||
static setShipAP(ship: Ship, points: number, recovery: number = 0): void {
|
static setShipAP(ship: Ship, points: number, recovery: number = 0): void {
|
||||||
var equipment = this.getOrGenEquipment(ship, SlotType.Power, new Equipments.NuclearReactor());
|
var equipment = this.getOrGenEquipment(ship, SlotType.Power, new Equipments.NuclearReactor());
|
||||||
|
|
|
@ -26,7 +26,7 @@ module TK.SpaceTac {
|
||||||
let battle = new Battle();
|
let battle = new Battle();
|
||||||
let ship = battle.fleets[0].addShip();
|
let ship = battle.fleets[0].addShip();
|
||||||
ship.setArenaPosition(0, 0);
|
ship.setArenaPosition(0, 0);
|
||||||
battle.playing_ship = ship;
|
TestTools.setShipPlaying(battle, ship);
|
||||||
TestTools.setShipAP(ship, 3);
|
TestTools.setShipAP(ship, 3);
|
||||||
let equipment = new Equipment(SlotType.Weapon, "testdrone");
|
let equipment = new Equipment(SlotType.Weapon, "testdrone");
|
||||||
let action = new DeployDroneAction(equipment, 2, 8, 2, 4, [new DamageEffect(50)]);
|
let action = new DeployDroneAction(equipment, 2, 8, 2, 4, [new DamageEffect(50)]);
|
||||||
|
|
|
@ -20,11 +20,11 @@ module TK.SpaceTac.Specs {
|
||||||
let battle = Battle.newQuickRandom();
|
let battle = Battle.newQuickRandom();
|
||||||
let action = new EndTurnAction();
|
let action = new EndTurnAction();
|
||||||
|
|
||||||
expect(battle.playing_ship_index).toBe(0);
|
expect(battle.play_index).toBe(0);
|
||||||
|
|
||||||
let result = action.apply(battle.play_order[0], Target.newFromShip(battle.play_order[0]));
|
let result = action.apply(battle.play_order[0], Target.newFromShip(battle.play_order[0]));
|
||||||
expect(result).toBe(true);
|
expect(result).toBe(true);
|
||||||
expect(battle.playing_ship_index).toBe(1);
|
expect(battle.play_index).toBe(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ module TK.SpaceTac {
|
||||||
it("checks movement against remaining AP", function () {
|
it("checks movement against remaining AP", function () {
|
||||||
var ship = new Ship();
|
var ship = new Ship();
|
||||||
var battle = new Battle(ship.fleet);
|
var battle = new Battle(ship.fleet);
|
||||||
battle.playing_ship = ship;
|
TestTools.setShipPlaying(battle, ship);
|
||||||
ship.values.power.setMaximal(20);
|
ship.values.power.setMaximal(20);
|
||||||
ship.values.power.set(6);
|
ship.values.power.set(6);
|
||||||
ship.arena_x = 0;
|
ship.arena_x = 0;
|
||||||
|
@ -45,7 +45,7 @@ module TK.SpaceTac {
|
||||||
ship.arena_y = 0;
|
ship.arena_y = 0;
|
||||||
var engine = new Equipment();
|
var engine = new Equipment();
|
||||||
var action = new MoveAction(engine, 1);
|
var action = new MoveAction(engine, 1);
|
||||||
battle.playing_ship = ship;
|
TestTools.setShipPlaying(battle, ship);
|
||||||
|
|
||||||
spyOn(console, "warn").and.stub();
|
spyOn(console, "warn").and.stub();
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ module TK.SpaceTac {
|
||||||
|
|
||||||
let battle = new Battle(fleet);
|
let battle = new Battle(fleet);
|
||||||
battle.play_order = [ship, ship1, ship2, ship3];
|
battle.play_order = [ship, ship1, ship2, ship3];
|
||||||
battle.playing_ship = ship;
|
TestTools.setShipPlaying(battle, ship);
|
||||||
fleet.setBattle(battle);
|
fleet.setBattle(battle);
|
||||||
|
|
||||||
action.apply(ship, Target.newFromLocation(50, 50));
|
action.apply(ship, Target.newFromLocation(50, 50));
|
||||||
|
|
|
@ -78,7 +78,7 @@ module TK.SpaceTac {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Run battle
|
// Run battle
|
||||||
while (!battle.ended && battle.turn < 100) {
|
while (!battle.ended && battle.cycle < 100) {
|
||||||
if (this.stopped) {
|
if (this.stopped) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ module TK.SpaceTac.Specs {
|
||||||
it("applies the highest evaluated maneuver", function () {
|
it("applies the highest evaluated maneuver", function () {
|
||||||
let battle = new Battle();
|
let battle = new Battle();
|
||||||
let ship = battle.fleets[0].addShip();
|
let ship = battle.fleets[0].addShip();
|
||||||
battle.playing_ship = ship;
|
TestTools.setShipPlaying(battle, ship);
|
||||||
ship.playing = true;
|
ship.playing = true;
|
||||||
let ai = new TacticalAI(ship, Timer.synchronous);
|
let ai = new TacticalAI(ship, Timer.synchronous);
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ module TK.SpaceTac.Specs {
|
||||||
let ship1b = battle.fleets[1].addShip(new Ship(null, "1B"));
|
let ship1b = battle.fleets[1].addShip(new Ship(null, "1B"));
|
||||||
|
|
||||||
TestTools.setShipAP(ship0a, 10);
|
TestTools.setShipAP(ship0a, 10);
|
||||||
battle.playing_ship = ship0a;
|
TestTools.setShipPlaying(battle, ship0a);
|
||||||
|
|
||||||
let result = imaterialize(TacticalAIHelpers.produceDirectShots(ship0a, battle));
|
let result = imaterialize(TacticalAIHelpers.produceDirectShots(ship0a, battle));
|
||||||
expect(result.length).toBe(0);
|
expect(result.length).toBe(0);
|
||||||
|
@ -30,7 +30,7 @@ module TK.SpaceTac.Specs {
|
||||||
let ship = battle.fleets[0].addShip();
|
let ship = battle.fleets[0].addShip();
|
||||||
|
|
||||||
TestTools.setShipAP(ship, 10);
|
TestTools.setShipAP(ship, 10);
|
||||||
battle.playing_ship = ship;
|
TestTools.setShipPlaying(battle, ship);
|
||||||
|
|
||||||
let result = imaterialize(TacticalAIHelpers.produceRandomMoves(ship, battle, 2, 1));
|
let result = imaterialize(TacticalAIHelpers.produceRandomMoves(ship, battle, 2, 1));
|
||||||
expect(result.length).toBe(0);
|
expect(result.length).toBe(0);
|
||||||
|
@ -52,7 +52,7 @@ module TK.SpaceTac.Specs {
|
||||||
let weapon = TestTools.addWeapon(ship, 50, 1, 1000, 105);
|
let weapon = TestTools.addWeapon(ship, 50, 1, 1000, 105);
|
||||||
|
|
||||||
TestTools.setShipAP(ship, 10);
|
TestTools.setShipAP(ship, 10);
|
||||||
battle.playing_ship = ship;
|
TestTools.setShipPlaying(battle, ship);
|
||||||
|
|
||||||
let result = imaterialize(TacticalAIHelpers.produceInterestingBlastShots(ship, battle));
|
let result = imaterialize(TacticalAIHelpers.produceInterestingBlastShots(ship, battle));
|
||||||
expect(result.length).toBe(0);
|
expect(result.length).toBe(0);
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
module TK.SpaceTac.Specs {
|
module TK.SpaceTac.Specs {
|
||||||
describe("DamageEffect", function () {
|
describe("DamageEffect", function () {
|
||||||
it("applies damage and wear", function () {
|
it("applies damage and wear", function () {
|
||||||
var ship = new Ship();
|
let battle = new Battle();
|
||||||
|
let ship = battle.fleets[0].addShip();
|
||||||
|
|
||||||
TestTools.setShipHP(ship, 150, 400);
|
TestTools.setShipHP(ship, 150, 400);
|
||||||
let hull = ship.listEquipment(SlotType.Hull)[0];
|
let hull = ship.listEquipment(SlotType.Hull)[0];
|
||||||
|
|
|
@ -40,8 +40,7 @@ module TK.SpaceTac.Equipments {
|
||||||
ship1.setArenaPosition(0, 0);
|
ship1.setArenaPosition(0, 0);
|
||||||
ship2.setArenaPosition(100, 0);
|
ship2.setArenaPosition(100, 0);
|
||||||
ship3.setArenaPosition(800, 0);
|
ship3.setArenaPosition(800, 0);
|
||||||
battle.playing_ship = ship1;
|
TestTools.setShipPlaying(battle, ship1);
|
||||||
ship1.playing = true;
|
|
||||||
expect(ship1.getAvailableActions()).toEqual([action, new EndTurnAction()]);
|
expect(ship1.getAvailableActions()).toEqual([action, new EndTurnAction()]);
|
||||||
|
|
||||||
TestTools.setShipHP(ship1, 100, 0);
|
TestTools.setShipHP(ship1, 100, 0);
|
||||||
|
|
|
@ -38,8 +38,7 @@ module TK.SpaceTac.Equipments {
|
||||||
|
|
||||||
let battle = new Battle();
|
let battle = new Battle();
|
||||||
let ship = battle.fleets[0].addShip();
|
let ship = battle.fleets[0].addShip();
|
||||||
battle.playing_ship = ship;
|
TestTools.setShipPlaying(battle, ship);
|
||||||
battle.play_order = [ship];
|
|
||||||
TestTools.setShipAP(ship, 10);
|
TestTools.setShipAP(ship, 10);
|
||||||
let result = nn(equipment.action).apply(ship, new Target(5, 5, null));
|
let result = nn(equipment.action).apply(ship, new Target(5, 5, null));
|
||||||
expect(result).toBe(true);
|
expect(result).toBe(true);
|
||||||
|
|
|
@ -28,7 +28,16 @@ module TK.SpaceTac {
|
||||||
*
|
*
|
||||||
* By default it does nothing
|
* By default it does nothing
|
||||||
*/
|
*/
|
||||||
apply(battle: Battle) {
|
apply(battle: Battle): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverts the event from a battle state
|
||||||
|
*
|
||||||
|
* By default it applies the reverse event
|
||||||
|
*/
|
||||||
|
revert(battle: Battle): void {
|
||||||
|
this.getReverse().apply(battle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
39
src/core/events/DeathEvent.spec.ts
Normal file
39
src/core/events/DeathEvent.spec.ts
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
/// <reference path="../../common/Testing.ts" />
|
||||||
|
|
||||||
|
module TK.SpaceTac.Specs {
|
||||||
|
testing("DeathEvent", test => {
|
||||||
|
test.case("applies and reverts", check => {
|
||||||
|
let battle = new Battle();
|
||||||
|
let ship1 = battle.fleets[0].addShip();
|
||||||
|
let ship2 = battle.fleets[0].addShip();
|
||||||
|
let ship3 = battle.fleets[1].addShip();
|
||||||
|
battle.play_order = [ship3, ship2, ship1];
|
||||||
|
|
||||||
|
check.equals(ship2.alive, true, "alive");
|
||||||
|
check.equals(imaterialize(battle.iships(false)), [ship1, ship2, ship3], "in all ships");
|
||||||
|
check.equals(imaterialize(battle.iships(true)), [ship1, ship2, ship3], "in alive ships");
|
||||||
|
check.equals(battle.fleets[0].ships, [ship1, ship2], "fleet1");
|
||||||
|
check.equals(battle.fleets[1].ships, [ship3], "fleet2");
|
||||||
|
check.equals(battle.play_order, [ship3, ship2, ship1], "in play order");
|
||||||
|
|
||||||
|
let event = new DeathEvent(battle, ship2);
|
||||||
|
event.apply(battle);
|
||||||
|
|
||||||
|
check.equals(ship2.alive, false, "dead");
|
||||||
|
check.equals(imaterialize(battle.iships(false)), [ship1, ship2, ship3], "in all ships");
|
||||||
|
check.equals(imaterialize(battle.iships(true)), [ship1, ship3], "not in alive ships anymore");
|
||||||
|
check.equals(battle.fleets[0].ships, [ship1, ship2], "fleet1");
|
||||||
|
check.equals(battle.fleets[1].ships, [ship3], "fleet2");
|
||||||
|
check.equals(battle.play_order, [ship3, ship1], "removed from play order");
|
||||||
|
|
||||||
|
event.revert(battle);
|
||||||
|
|
||||||
|
check.equals(ship2.alive, true, "alive again");
|
||||||
|
check.equals(imaterialize(battle.iships(false)), [ship1, ship2, ship3], "in all ships");
|
||||||
|
check.equals(imaterialize(battle.iships(true)), [ship1, ship2, ship3], "back in alive ships");
|
||||||
|
check.equals(battle.fleets[0].ships, [ship1, ship2], "fleet1");
|
||||||
|
check.equals(battle.fleets[1].ships, [ship3], "fleet2");
|
||||||
|
check.equals(battle.play_order, [ship3, ship2, ship1], "back in play order");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -1,10 +1,48 @@
|
||||||
/// <reference path="BaseBattleEvent.ts"/>
|
/// <reference path="BaseBattleEvent.ts"/>
|
||||||
|
|
||||||
module TK.SpaceTac {
|
module TK.SpaceTac {
|
||||||
// Event logged when a ship is dead
|
/**
|
||||||
|
* A ship dies (or rather is put in emergency stasis mode)
|
||||||
|
*
|
||||||
|
* This typically happens when the ship's hull reaches 0.
|
||||||
|
* A dead ship cannot be interacted with, and will be removed from play order.
|
||||||
|
*/
|
||||||
export class DeathEvent extends BaseLogShipEvent {
|
export class DeathEvent extends BaseLogShipEvent {
|
||||||
constructor(ship: Ship) {
|
// Unique ID of the ship in the battle
|
||||||
|
ship_id: RObjectId
|
||||||
|
|
||||||
|
// Index in the play order at which the ship was
|
||||||
|
play_index: number
|
||||||
|
|
||||||
|
constructor(battle: Battle, ship: Ship) {
|
||||||
super("death", ship);
|
super("death", ship);
|
||||||
|
|
||||||
|
this.ship_id = ship.id;
|
||||||
|
this.play_index = battle.play_order.indexOf(ship);
|
||||||
|
}
|
||||||
|
|
||||||
|
apply(battle: Battle) {
|
||||||
|
let ship = battle.getShip(this.ship_id);
|
||||||
|
if (ship) {
|
||||||
|
ship.alive = false;
|
||||||
|
if (this.play_index >= 0) {
|
||||||
|
battle.removeFromPlayOrder(this.play_index);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn("Ship not found", this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
revert(battle: Battle) {
|
||||||
|
let ship = battle.getShip(this.ship_id);
|
||||||
|
if (ship) {
|
||||||
|
ship.alive = true;
|
||||||
|
if (this.play_index >= 0) {
|
||||||
|
battle.insertInPlayOrder(this.play_index, ship);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn("Ship not found", this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,27 @@
|
||||||
|
/// <reference path="../../common/Testing.ts" />
|
||||||
|
|
||||||
module TK.SpaceTac.Specs {
|
module TK.SpaceTac.Specs {
|
||||||
describe("ValueChangeEvent", function () {
|
testing("ValueChangeEvent", test => {
|
||||||
it("get reverse event", function () {
|
test.case("get reverse event", check => {
|
||||||
let ship = new Ship();
|
let ship = new Ship();
|
||||||
let event = new ValueChangeEvent(ship, new ShipValue("hull", 15, 22), 10);
|
let event = new ValueChangeEvent(ship, new ShipValue("hull", 15, 22), 10);
|
||||||
expect(event.getReverse()).toEqual(new ValueChangeEvent(ship, new ShipValue("hull", 5, 22), -10));
|
check.equals(event.getReverse(), new ValueChangeEvent(ship, new ShipValue("hull", 5, 22), -10));
|
||||||
|
});
|
||||||
|
|
||||||
|
test.case("applies and reverts", check => {
|
||||||
|
let battle = new Battle();
|
||||||
|
let ship = battle.fleets[0].addShip();
|
||||||
|
check.equals(ship.getValue("hull"), 0);
|
||||||
|
|
||||||
|
let events = ship.getValueEvents("hull", 15);
|
||||||
|
check.equals(ship.getValue("hull"), 0);
|
||||||
|
check.equals(events.length, 1);
|
||||||
|
|
||||||
|
events[0].apply(battle);
|
||||||
|
check.equals(ship.getValue("hull"), 15);
|
||||||
|
|
||||||
|
events[0].revert(battle);
|
||||||
|
check.equals(ship.getValue("hull"), 0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
|
@ -5,15 +5,19 @@ module TK.SpaceTac {
|
||||||
* Event logged when a ship value or attribute changed
|
* Event logged when a ship value or attribute changed
|
||||||
*/
|
*/
|
||||||
export class ValueChangeEvent extends BaseLogShipEvent {
|
export class ValueChangeEvent extends BaseLogShipEvent {
|
||||||
|
// Ship ID
|
||||||
|
ship_id: RObjectId
|
||||||
|
|
||||||
// Saved version of the current value
|
// Saved version of the current value
|
||||||
value: ShipValue;
|
value: ShipValue
|
||||||
|
|
||||||
// Value variation
|
// Value variation
|
||||||
diff: number;
|
diff: number
|
||||||
|
|
||||||
constructor(ship: Ship, value: ShipValue, diff: number) {
|
constructor(ship: Ship, value: ShipValue, diff: number) {
|
||||||
super("value", ship);
|
super("value", ship);
|
||||||
|
|
||||||
|
this.ship_id = ship.id;
|
||||||
this.value = copy(value);
|
this.value = copy(value);
|
||||||
this.diff = diff;
|
this.diff = diff;
|
||||||
}
|
}
|
||||||
|
@ -23,5 +27,14 @@ module TK.SpaceTac {
|
||||||
value.set(value.get() - this.diff);
|
value.set(value.get() - this.diff);
|
||||||
return new ValueChangeEvent(this.ship, value, -this.diff);
|
return new ValueChangeEvent(this.ship, value, -this.diff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apply(battle: Battle): void {
|
||||||
|
let ship = battle.getShip(this.ship_id);
|
||||||
|
if (ship) {
|
||||||
|
ship.setValue(<any>this.value.name, this.value.get(), false, false);
|
||||||
|
} else {
|
||||||
|
console.warn("Ship not found", this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
module TK.SpaceTac.Multi.Specs {
|
module TK.SpaceTac.Multi.Specs {
|
||||||
describe("Connection", function () {
|
testing("Connection", test => {
|
||||||
async_it("finds an unused token", async function () {
|
test.acase("finds an unused token", async check => {
|
||||||
let storage = new FakeRemoteStorage();
|
let storage = new FakeRemoteStorage();
|
||||||
let connection = new Connection("test", storage);
|
let connection = new Connection("test", storage);
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ module TK.SpaceTac.Multi.Specs {
|
||||||
expect(other).toEqual("123456");
|
expect(other).toEqual("123456");
|
||||||
});
|
});
|
||||||
|
|
||||||
async_it("loads a session by its id", async function () {
|
test.acase("loads a session by its id", async check => {
|
||||||
let session = new GameSession();
|
let session = new GameSession();
|
||||||
let serializer = new Serializer(TK.SpaceTac);
|
let serializer = new Serializer(TK.SpaceTac);
|
||||||
let storage = new FakeRemoteStorage();
|
let storage = new FakeRemoteStorage();
|
||||||
|
@ -42,7 +42,7 @@ module TK.SpaceTac.Multi.Specs {
|
||||||
expect(result).toBeNull();
|
expect(result).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
async_it("lists saves from a device", async function () {
|
test.acase("lists saves from a device", async check => {
|
||||||
let storage = new FakeRemoteStorage();
|
let storage = new FakeRemoteStorage();
|
||||||
let connection = new Connection("test", storage);
|
let connection = new Connection("test", storage);
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ module TK.SpaceTac.Multi.Specs {
|
||||||
expect(result).toEqual({ abc: "ABC", cba: "CBA" });
|
expect(result).toEqual({ abc: "ABC", cba: "CBA" });
|
||||||
});
|
});
|
||||||
|
|
||||||
async_it("publishes saves and retrieves them by token", async function () {
|
test.acase("publishes saves and retrieves them by token", async check => {
|
||||||
let session = new GameSession();
|
let session = new GameSession();
|
||||||
let storage = new FakeRemoteStorage();
|
let storage = new FakeRemoteStorage();
|
||||||
let connection = new Connection("test", storage);
|
let connection = new Connection("test", storage);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
module TK.SpaceTac.Multi.Specs {
|
module TK.SpaceTac.Multi.Specs {
|
||||||
describe("Exchange", function () {
|
testing("Exchange", test => {
|
||||||
function newExchange(token: string, storage = new FakeRemoteStorage()): [FakeRemoteStorage, Exchange, Exchange] {
|
function newExchange(token: string, storage = new FakeRemoteStorage()): [FakeRemoteStorage, Exchange, Exchange] {
|
||||||
let connection = new Connection("test", storage);
|
let connection = new Connection("test", storage);
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ module TK.SpaceTac.Multi.Specs {
|
||||||
spyOn(console, "log").and.stub();
|
spyOn(console, "log").and.stub();
|
||||||
});
|
});
|
||||||
|
|
||||||
async_it("says hello on start", async function () {
|
test.acase("says hello on start", async function () {
|
||||||
let [storage, peer1, peer2] = newExchange("abc");
|
let [storage, peer1, peer2] = newExchange("abc");
|
||||||
spyOn(peer1, "getNextId").and.returnValues("1A", "1B", "1C");
|
spyOn(peer1, "getNextId").and.returnValues("1A", "1B", "1C");
|
||||||
spyOn(peer2, "getNextId").and.returnValues("2A", "2B", "2C");
|
spyOn(peer2, "getNextId").and.returnValues("2A", "2B", "2C");
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
module TK.SpaceTac.Multi.Specs {
|
module TK.SpaceTac.Multi.Specs {
|
||||||
describe("FakeRemoteStorage", function () {
|
testing("FakeRemoteStorage", test => {
|
||||||
async_it("can fetch a single record", async function () {
|
test.acase("can fetch a single record", async function () {
|
||||||
let storage = new FakeRemoteStorage();
|
let storage = new FakeRemoteStorage();
|
||||||
|
|
||||||
let result = await storage.find("test", { key: 5 });
|
let result = await storage.find("test", { key: 5 });
|
||||||
|
@ -21,7 +21,7 @@ module TK.SpaceTac.Multi.Specs {
|
||||||
expect(result).toBeNull();
|
expect(result).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
async_it("inserts or updates objects", async function () {
|
test.acase("inserts or updates objects", async function () {
|
||||||
let storage = new FakeRemoteStorage();
|
let storage = new FakeRemoteStorage();
|
||||||
|
|
||||||
let result = await storage.search("test", { key: 5 });
|
let result = await storage.search("test", { key: 5 });
|
||||||
|
|
|
@ -241,17 +241,21 @@ module TK.SpaceTac.UI {
|
||||||
*/
|
*/
|
||||||
getImageInfo(name: string): { key: string, frame: number } {
|
getImageInfo(name: string): { key: string, frame: number } {
|
||||||
// TODO Cache
|
// TODO Cache
|
||||||
let i = 1;
|
if (this.game.cache.checkImageKey(name)) {
|
||||||
while (this.game.cache.checkImageKey(`atlas-${i}`)) {
|
return { key: name, frame: 0 };
|
||||||
let data = this.game.cache.getFrameData(`atlas-${i}`);
|
} else {
|
||||||
let frames = data.getFrames();
|
let i = 1;
|
||||||
let frame = first(frames, frame => AssetLoading.getKey(frame.name) == `graphics-exported-${name}`);
|
while (this.game.cache.checkImageKey(`atlas-${i}`)) {
|
||||||
if (frame) {
|
let data = this.game.cache.getFrameData(`atlas-${i}`);
|
||||||
return { key: `atlas-${i}`, frame: frame.index };
|
let frames = data.getFrames();
|
||||||
|
let frame = first(frames, frame => AssetLoading.getKey(frame.name) == `graphics-exported-${name}`);
|
||||||
|
if (frame) {
|
||||||
|
return { key: `atlas-${i}`, frame: frame.index };
|
||||||
|
}
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
i++;
|
return { key: `-missing-${name}`, frame: 0 };
|
||||||
}
|
}
|
||||||
return { key: `-missing-${name}`, frame: 0 };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -121,7 +121,7 @@ module TK.SpaceTac.UI {
|
||||||
this.updateEffectsRadius();
|
this.updateEffectsRadius();
|
||||||
|
|
||||||
// Set location
|
// Set location
|
||||||
if (this.battleview.battle.turn == 1 && ship.alive && ship.fleet.player === this.battleview.player) {
|
if (this.battleview.battle.cycle == 1 && this.battleview.battle.play_index == 0 && ship.alive && ship.fleet.player === this.battleview.player) {
|
||||||
this.position.set(ship.arena_x - 500 * Math.cos(ship.arena_angle), ship.arena_y - 500 * Math.sin(ship.arena_angle));
|
this.position.set(ship.arena_x - 500 * Math.cos(ship.arena_angle), ship.arena_y - 500 * Math.sin(ship.arena_angle));
|
||||||
this.moveTo(ship.arena_x, ship.arena_y, ship.arena_angle);
|
this.moveTo(ship.arena_x, ship.arena_y, ship.arena_angle);
|
||||||
} else {
|
} else {
|
||||||
|
@ -145,7 +145,7 @@ module TK.SpaceTac.UI {
|
||||||
if (event.new_ship === this.ship) {
|
if (event.new_ship === this.ship) {
|
||||||
this.play_order.text = "-";
|
this.play_order.text = "-";
|
||||||
} else {
|
} else {
|
||||||
this.play_order.text = this.battleview.battle.getTurnsBefore(this.ship).toString();
|
this.play_order.text = this.battleview.battle.getPlayOrder(this.ship).toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -1,8 +1,19 @@
|
||||||
/// <reference path="../BaseView.ts"/>
|
/// <reference path="../BaseView.ts"/>
|
||||||
|
|
||||||
module TK.SpaceTac.UI {
|
module TK.SpaceTac.UI {
|
||||||
// Interactive view of a Battle
|
/**
|
||||||
export class BattleView extends BaseView {
|
* Interface for interacting with a ship (hover and click)
|
||||||
|
*/
|
||||||
|
export interface IShipButton {
|
||||||
|
cursorOnShip: (ship: Ship) => void;
|
||||||
|
cursorOffShip: (ship: Ship) => void;
|
||||||
|
cursorClicked: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interactive view of a Battle
|
||||||
|
*/
|
||||||
|
export class BattleView extends BaseView implements IShipButton {
|
||||||
// Displayed battle
|
// Displayed battle
|
||||||
battle: Battle
|
battle: Battle
|
||||||
|
|
||||||
|
@ -102,8 +113,8 @@ module TK.SpaceTac.UI {
|
||||||
// Add UI elements
|
// Add UI elements
|
||||||
this.action_bar = new ActionBar(this);
|
this.action_bar = new ActionBar(this);
|
||||||
this.action_bar.position.set(0, this.getHeight() - 132);
|
this.action_bar.position.set(0, this.getHeight() - 132);
|
||||||
this.ship_list = new ShipList(this);
|
this.ship_list = new ShipList(this, this.battle, this.player, this.toggle_tactical_mode, this,
|
||||||
this.ship_list.position.set(this.getWidth() - 112, 0);
|
this.layer_borders, this.getWidth() - 112, 0);
|
||||||
this.ship_tooltip = new ShipTooltip(this);
|
this.ship_tooltip = new ShipTooltip(this);
|
||||||
this.character_sheet = new CharacterSheet(this, -this.getWidth());
|
this.character_sheet = new CharacterSheet(this, -this.getWidth());
|
||||||
this.layer_sheets.add(this.character_sheet);
|
this.layer_sheets.add(this.character_sheet);
|
||||||
|
@ -179,7 +190,7 @@ module TK.SpaceTac.UI {
|
||||||
numberPressed(num: number): void {
|
numberPressed(num: number): void {
|
||||||
if (this.interacting) {
|
if (this.interacting) {
|
||||||
if (this.targetting.active) {
|
if (this.targetting.active) {
|
||||||
let ship = ifirst(this.battle.iships(true), ship => this.battle.getTurnsBefore(ship) == num % 10);
|
let ship = ifirst(this.battle.iships(true), ship => this.battle.getPlayOrder(ship) == num % 10);
|
||||||
if (ship) {
|
if (ship) {
|
||||||
this.targetting.setTarget(Target.newFromShip(ship));
|
this.targetting.setTarget(Target.newFromShip(ship));
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ module TK.SpaceTac.UI.Specs {
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(battle: Battle) {
|
apply(battle: Battle) {
|
||||||
battle.turn += this.diff;
|
battle.cycle += this.diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
getReverse(): BaseBattleEvent {
|
getReverse(): BaseBattleEvent {
|
||||||
|
@ -31,42 +31,42 @@ module TK.SpaceTac.UI.Specs {
|
||||||
event.apply(battle);
|
event.apply(battle);
|
||||||
return 0;
|
return 0;
|
||||||
});
|
});
|
||||||
expect(battle.turn).toBe(1);
|
expect(battle.cycle).toBe(1);
|
||||||
expect(processor.atStart()).toBe(true);
|
expect(processor.atStart()).toBe(true);
|
||||||
expect(processor.atEnd()).toBe(true);
|
expect(processor.atEnd()).toBe(true);
|
||||||
|
|
||||||
processor.stepForward();
|
processor.stepForward();
|
||||||
expect(battle.turn).toBe(1);
|
expect(battle.cycle).toBe(1);
|
||||||
expect(processor.atStart()).toBe(true);
|
expect(processor.atStart()).toBe(true);
|
||||||
expect(processor.atEnd()).toBe(true);
|
expect(processor.atEnd()).toBe(true);
|
||||||
|
|
||||||
battle.log.add(new FakeEvent());
|
battle.log.add(new FakeEvent());
|
||||||
expect(battle.turn).toBe(1);
|
expect(battle.cycle).toBe(1);
|
||||||
expect(processor.atStart()).toBe(true);
|
expect(processor.atStart()).toBe(true);
|
||||||
expect(processor.atEnd()).toBe(false);
|
expect(processor.atEnd()).toBe(false);
|
||||||
|
|
||||||
processor.stepForward();
|
processor.stepForward();
|
||||||
expect(battle.turn).toBe(2);
|
expect(battle.cycle).toBe(2);
|
||||||
expect(processor.atStart()).toBe(false);
|
expect(processor.atStart()).toBe(false);
|
||||||
expect(processor.atEnd()).toBe(true);
|
expect(processor.atEnd()).toBe(true);
|
||||||
|
|
||||||
processor.stepForward();
|
processor.stepForward();
|
||||||
expect(battle.turn).toBe(2);
|
expect(battle.cycle).toBe(2);
|
||||||
expect(processor.atStart()).toBe(false);
|
expect(processor.atStart()).toBe(false);
|
||||||
expect(processor.atEnd()).toBe(true);
|
expect(processor.atEnd()).toBe(true);
|
||||||
|
|
||||||
processor.stepBackward();
|
processor.stepBackward();
|
||||||
expect(battle.turn).toBe(1);
|
expect(battle.cycle).toBe(1);
|
||||||
expect(processor.atStart()).toBe(true);
|
expect(processor.atStart()).toBe(true);
|
||||||
expect(processor.atEnd()).toBe(false);
|
expect(processor.atEnd()).toBe(false);
|
||||||
|
|
||||||
processor.stepBackward();
|
processor.stepBackward();
|
||||||
expect(battle.turn).toBe(1);
|
expect(battle.cycle).toBe(1);
|
||||||
expect(processor.atStart()).toBe(true);
|
expect(processor.atStart()).toBe(true);
|
||||||
expect(processor.atEnd()).toBe(false);
|
expect(processor.atEnd()).toBe(false);
|
||||||
|
|
||||||
processor.stepForward();
|
processor.stepForward();
|
||||||
expect(battle.turn).toBe(2);
|
expect(battle.cycle).toBe(2);
|
||||||
expect(processor.atStart()).toBe(false);
|
expect(processor.atStart()).toBe(false);
|
||||||
expect(processor.atEnd()).toBe(true);
|
expect(processor.atEnd()).toBe(true);
|
||||||
})
|
})
|
||||||
|
|
|
@ -288,7 +288,7 @@ module TK.SpaceTac.UI {
|
||||||
private processShipChangeEvent(event: ShipChangeEvent): number {
|
private processShipChangeEvent(event: ShipChangeEvent): number {
|
||||||
this.current_ship = event.new_ship;
|
this.current_ship = event.new_ship;
|
||||||
this.view.arena.setShipPlaying(event.new_ship);
|
this.view.arena.setShipPlaying(event.new_ship);
|
||||||
this.view.ship_list.setPlaying(event.new_ship);
|
this.view.ship_list.refresh(!event.initial);
|
||||||
if (event.ship !== event.new_ship) {
|
if (event.ship !== event.new_ship) {
|
||||||
this.view.audio.playOnce("battle-ship-change");
|
this.view.audio.playOnce("battle-ship-change");
|
||||||
}
|
}
|
||||||
|
@ -306,13 +306,19 @@ module TK.SpaceTac.UI {
|
||||||
|
|
||||||
// A ship died
|
// A ship died
|
||||||
private processDeathEvent(event: DeathEvent): number {
|
private processDeathEvent(event: DeathEvent): number {
|
||||||
if (this.view.ship_hovered === event.ship) {
|
let ship = this.battle.getShip(event.ship_id);
|
||||||
this.view.setShipHovered(null);
|
|
||||||
}
|
|
||||||
this.view.arena.markAsDead(event.ship);
|
|
||||||
this.view.ship_list.markAsDead(event.ship);
|
|
||||||
|
|
||||||
return event.initial ? 0 : 1000;
|
if (ship) {
|
||||||
|
if (this.view.ship_hovered === ship) {
|
||||||
|
this.view.setShipHovered(null);
|
||||||
|
}
|
||||||
|
this.view.arena.markAsDead(ship);
|
||||||
|
this.view.ship_list.refresh(!event.initial);
|
||||||
|
|
||||||
|
return event.initial ? 0 : 3000;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Weapon used
|
// Weapon used
|
||||||
|
|
|
@ -1,26 +1,65 @@
|
||||||
/// <reference path="../TestGame.ts"/>
|
/// <reference path="../TestGame.ts"/>
|
||||||
|
|
||||||
module TK.SpaceTac.UI.Specs {
|
module TK.SpaceTac.UI.Specs {
|
||||||
describe("ShipList", function () {
|
testing("ShipList", test => {
|
||||||
let testgame = setupBattleview();
|
let testgame = setupEmptyView();
|
||||||
|
|
||||||
it("handles play position of ships", function () {
|
function createList(): ShipList {
|
||||||
let battleview = testgame.view;
|
let view = testgame.view;
|
||||||
var list = battleview.ship_list;
|
let battle = new Battle();
|
||||||
|
let tactical_mode = new Toggle();
|
||||||
|
let ship_buttons = jasmine.createSpyObj("ship_buttons", ["cursorOnShip", "cursorOffShip", "cursorClicked"]);
|
||||||
|
let list = new ShipList(view, battle, battle.fleets[0].player, tactical_mode, ship_buttons);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
expect(battleview.battle.play_order.length).toBe(10);
|
test.case("handles play position of ships", check => {
|
||||||
expect(list.children.length).toBe(11);
|
let list = createList();
|
||||||
|
let battle = list.battle;
|
||||||
|
check.equals(list.items.length, 0, "no item at first");
|
||||||
|
|
||||||
expect(list.findPlayPosition(battleview.battle.play_order[0])).toBe(0);
|
battle.fleets[0].addShip();
|
||||||
expect(list.findPlayPosition(battleview.battle.play_order[1])).toBe(1);
|
list.setShipsFromBattle(battle, false);
|
||||||
expect(list.findPlayPosition(battleview.battle.play_order[2])).toBe(2);
|
check.equals(list.items.length, 1, "one ship added but not in play order");
|
||||||
|
check.equals(list.items[0].visible, false, "one ship added but not in play order");
|
||||||
|
|
||||||
spyOn(battleview.battle, "playAI").and.stub();
|
battle.throwInitiative();
|
||||||
battleview.battle.advanceToNextShip();
|
list.refresh(false);
|
||||||
|
check.equals(list.items[0].visible, true, "ship now in play order");
|
||||||
|
|
||||||
expect(list.findPlayPosition(battleview.battle.play_order[0])).toBe(9);
|
battle.fleets[1].addShip();
|
||||||
expect(list.findPlayPosition(battleview.battle.play_order[1])).toBe(0);
|
battle.throwInitiative();
|
||||||
expect(list.findPlayPosition(battleview.battle.play_order[2])).toBe(1);
|
list.setShipsFromBattle(battle, false);
|
||||||
|
check.equals(list.items.length, 2, "ship added in the other fleet");
|
||||||
|
check.equals(nn(list.findItem(battle.play_order[0])).position, new Phaser.Point(2, 843));
|
||||||
|
check.equals(nn(list.findItem(battle.play_order[1])).position, new Phaser.Point(2, 744));
|
||||||
|
|
||||||
|
battle.advanceToNextShip();
|
||||||
|
list.refresh(false);
|
||||||
|
check.equals(nn(list.findItem(battle.play_order[0])).position, new Phaser.Point(-18, 962));
|
||||||
|
check.equals(nn(list.findItem(battle.play_order[1])).position, new Phaser.Point(2, 843));
|
||||||
|
|
||||||
|
battle.advanceToNextShip();
|
||||||
|
list.refresh(false);
|
||||||
|
check.equals(nn(list.findItem(battle.play_order[0])).position, new Phaser.Point(2, 843));
|
||||||
|
check.equals(nn(list.findItem(battle.play_order[1])).position, new Phaser.Point(-18, 962));
|
||||||
|
|
||||||
|
battle.fleets[1].addShip();
|
||||||
|
battle.throwInitiative();
|
||||||
|
battle.advanceToNextShip();
|
||||||
|
list.setShipsFromBattle(battle, false);
|
||||||
|
check.equals(list.items.length, 3, "three ships");
|
||||||
|
check.equals(nn(list.findItem(battle.play_order[0])).position, new Phaser.Point(-18, 962));
|
||||||
|
check.equals(nn(list.findItem(battle.play_order[1])).position, new Phaser.Point(2, 843));
|
||||||
|
check.equals(nn(list.findItem(battle.play_order[2])).position, new Phaser.Point(2, 744));
|
||||||
|
|
||||||
|
let dead = battle.play_order[1];
|
||||||
|
dead.setDead();
|
||||||
|
list.refresh(false);
|
||||||
|
check.equals(list.items.length, 3, "dead ship");
|
||||||
|
check.equals(nn(list.findItem(battle.play_order[0])).position, new Phaser.Point(-18, 962));
|
||||||
|
check.equals(nn(list.findItem(dead)).position, new Phaser.Point(200, 843));
|
||||||
|
check.equals(nn(list.findItem(battle.play_order[1])).position, new Phaser.Point(2, 843));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,126 +1,117 @@
|
||||||
module TK.SpaceTac.UI {
|
module TK.SpaceTac.UI {
|
||||||
// Bar with all playing ships, by play order
|
/**
|
||||||
export class ShipList extends Phaser.Image {
|
* Side bar with all playing ships, sorted by play order
|
||||||
// Link to the parent battleview
|
*/
|
||||||
battleview: BattleView;
|
export class ShipList {
|
||||||
|
// Link to the parent view
|
||||||
|
view: BaseView
|
||||||
|
|
||||||
|
// Current battle
|
||||||
|
battle: Battle
|
||||||
|
|
||||||
|
// Current player
|
||||||
|
player: Player
|
||||||
|
|
||||||
|
// Interface for acting as ship button
|
||||||
|
ship_buttons: IShipButton
|
||||||
|
|
||||||
|
// Container
|
||||||
|
container: Phaser.Image
|
||||||
|
|
||||||
// List of ship items
|
// List of ship items
|
||||||
ships_container: Phaser.Group;
|
items: ShipListItem[]
|
||||||
ships: ShipListItem[];
|
|
||||||
|
|
||||||
// Playing ship
|
|
||||||
playing: ShipListItem | null;
|
|
||||||
|
|
||||||
// Hovered ship
|
// Hovered ship
|
||||||
hovered: ShipListItem | null;
|
hovered: ShipListItem | null
|
||||||
|
|
||||||
// Info button
|
// Info button
|
||||||
info_button: Phaser.Button;
|
info_button: Phaser.Button
|
||||||
|
|
||||||
// Create an empty action bar
|
constructor(view: BaseView, battle: Battle, player: Player, tactical_mode: Toggle, ship_buttons: IShipButton, parent?: UIContainer, x = 0, y = 0) {
|
||||||
constructor(battleview: BattleView) {
|
let builder = new UIBuilder(view, parent);
|
||||||
super(battleview.game, 0, 0, "battle-shiplist-background");
|
this.container = builder.image("battle-shiplist-background", x, y);
|
||||||
|
|
||||||
this.battleview = battleview;
|
this.view = view;
|
||||||
this.ships = [];
|
// TODO Should use an UI game state, not the actual game state
|
||||||
this.playing = null;
|
this.battle = battle;
|
||||||
|
this.player = player;
|
||||||
|
this.ship_buttons = ship_buttons;
|
||||||
|
|
||||||
|
this.items = [];
|
||||||
this.hovered = null;
|
this.hovered = null;
|
||||||
|
|
||||||
this.info_button = new Phaser.Button(this.game, 0, 0, "battle-shiplist-info-button");
|
this.info_button = new Phaser.Button(view.game, 0, 0, "battle-shiplist-info-button");
|
||||||
this.battleview.inputs.setHoverClick(this.info_button,
|
this.view.inputs.setHoverClick(this.info_button,
|
||||||
() => this.battleview.toggle_tactical_mode.manipulate("button")(true),
|
() => tactical_mode.manipulate("shiplist")(true),
|
||||||
() => this.battleview.toggle_tactical_mode.manipulate("button")(false),
|
() => tactical_mode.manipulate("shiplist")(false),
|
||||||
() => null);
|
() => null);
|
||||||
this.addChild(this.info_button);
|
this.container.addChild(this.info_button);
|
||||||
|
|
||||||
battleview.layer_borders.add(this);
|
this.setShipsFromBattle(battle);
|
||||||
|
|
||||||
if (battleview.battle) {
|
|
||||||
this.setShipsFromBattle(battleview.battle);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear the action icons
|
/**
|
||||||
|
* Clear all ship cards
|
||||||
|
*/
|
||||||
clearAll(): void {
|
clearAll(): void {
|
||||||
this.ships.forEach((ship: ShipListItem) => {
|
this.items.forEach(ship => ship.destroy());
|
||||||
ship.destroy();
|
this.items = [];
|
||||||
});
|
|
||||||
this.ships = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the ship list from a battle
|
/**
|
||||||
setShipsFromBattle(battle: Battle): void {
|
* Rebuild the ship list from an ongoing battle
|
||||||
|
*/
|
||||||
|
setShipsFromBattle(battle: Battle, animate = true): void {
|
||||||
this.clearAll();
|
this.clearAll();
|
||||||
battle.play_order.forEach((ship: Ship) => {
|
iforeach(battle.iships(true), ship => this.addShip(ship));
|
||||||
this.addShip(ship);
|
this.refresh(animate);
|
||||||
}, this);
|
|
||||||
this.updateItemsLocation();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a ship icon
|
/**
|
||||||
|
* Add a ship card
|
||||||
|
*/
|
||||||
addShip(ship: Ship): ShipListItem {
|
addShip(ship: Ship): ShipListItem {
|
||||||
var owned = ship.getPlayer() === this.battleview.player;
|
var owned = ship.getPlayer() === this.player;
|
||||||
var result = new ShipListItem(this, 200, this.height / 2, ship, owned);
|
var result = new ShipListItem(this, 200, this.container.height / 2, ship, owned, this.ship_buttons);
|
||||||
this.ships.push(result);
|
this.items.push(result);
|
||||||
this.addChild(result);
|
this.container.addChild(result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find an item for a ship
|
/**
|
||||||
// Returns null if not found
|
* Find the item (card) that displays a given ship
|
||||||
|
*/
|
||||||
findItem(ship: Ship): ShipListItem | null {
|
findItem(ship: Ship): ShipListItem | null {
|
||||||
var found: ShipListItem | null = null;
|
return first(this.items, item => item.ship == ship);
|
||||||
this.ships.forEach((item: ShipListItem) => {
|
|
||||||
if (item.ship === ship) {
|
|
||||||
found = item;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return found;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the play position in play_order for a given ship (0 is currently playing)
|
/**
|
||||||
findPlayPosition(ship: Ship): number {
|
* Update the locations of all items
|
||||||
var battle = this.battleview.battle;
|
*/
|
||||||
var idx = battle.play_order.indexOf(ship);
|
refresh(animate = true): void {
|
||||||
var diff = idx - (battle.playing_ship_index || 0);
|
this.items.forEach(item => {
|
||||||
if (diff < 0) {
|
if (item.ship.alive) {
|
||||||
diff += battle.play_order.length;
|
let position = this.battle.getPlayOrder(item.ship);
|
||||||
}
|
if (position < 0) {
|
||||||
return diff;
|
item.visible = false;
|
||||||
}
|
} else {
|
||||||
|
if (position == 0) {
|
||||||
// Update the locations of all items
|
item.moveTo(-18, 962, animate ? 1000 : 0);
|
||||||
updateItemsLocation(animate: boolean = true): void {
|
} else {
|
||||||
this.ships.forEach((item: ShipListItem) => {
|
item.moveTo(2, 942 - position * 99, animate ? 1000 : 0);
|
||||||
var position = this.findPlayPosition(item.ship);
|
}
|
||||||
if (position === 0) {
|
item.visible = true;
|
||||||
item.moveTo(-18, 962, animate);
|
this.container.setChildIndex(item, position);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
item.moveTo(2, 942 - position * 99, animate);
|
item.moveTo(200, item.y, animate ? 1000 : 0);
|
||||||
}
|
}
|
||||||
this.setChildIndex(item, position);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove a ship from the list
|
/**
|
||||||
markAsDead(ship: Ship): void {
|
* Set the currently hovered ship
|
||||||
var item = this.findItem(ship);
|
*/
|
||||||
if (item) {
|
|
||||||
item.alpha = 0.5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the currently playing ship
|
|
||||||
setPlaying(ship: Ship | null): void {
|
|
||||||
if (ship) {
|
|
||||||
this.playing = this.findItem(ship);
|
|
||||||
} else {
|
|
||||||
this.playing = null;
|
|
||||||
}
|
|
||||||
this.updateItemsLocation();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the currently hovered ship
|
|
||||||
setHovered(ship: Ship | null): void {
|
setHovered(ship: Ship | null): void {
|
||||||
if (this.hovered) {
|
if (this.hovered) {
|
||||||
this.hovered.setHovered(false);
|
this.hovered.setHovered(false);
|
||||||
|
|
|
@ -2,11 +2,14 @@ module TK.SpaceTac.UI {
|
||||||
// One item in a ship list (used in BattleView)
|
// One item in a ship list (used in BattleView)
|
||||||
export class ShipListItem extends Phaser.Button {
|
export class ShipListItem extends Phaser.Button {
|
||||||
// Reference to the view
|
// Reference to the view
|
||||||
view: BattleView
|
view: BaseView
|
||||||
|
|
||||||
// Reference to the ship game object
|
// Reference to the ship game object
|
||||||
ship: Ship
|
ship: Ship
|
||||||
|
|
||||||
|
// Callbacks to act as buttons
|
||||||
|
ship_buttons: IShipButton
|
||||||
|
|
||||||
// Player indicator
|
// Player indicator
|
||||||
player_indicator: Phaser.Image
|
player_indicator: Phaser.Image
|
||||||
|
|
||||||
|
@ -20,9 +23,9 @@ module TK.SpaceTac.UI {
|
||||||
hover_indicator: Phaser.Image
|
hover_indicator: Phaser.Image
|
||||||
|
|
||||||
// Create a ship button for the battle ship list
|
// Create a ship button for the battle ship list
|
||||||
constructor(list: ShipList, x: number, y: number, ship: Ship, owned: boolean) {
|
constructor(list: ShipList, x: number, y: number, ship: Ship, owned: boolean, ship_buttons: IShipButton) {
|
||||||
super(list.battleview.game, x, y, "battle-shiplist-item-background");
|
super(list.view.game, x, y, "battle-shiplist-item-background");
|
||||||
this.view = list.battleview;
|
this.view = list.view;
|
||||||
|
|
||||||
this.ship = ship;
|
this.ship = ship;
|
||||||
|
|
||||||
|
@ -44,9 +47,9 @@ module TK.SpaceTac.UI {
|
||||||
this.addChild(this.hover_indicator);
|
this.addChild(this.hover_indicator);
|
||||||
|
|
||||||
this.view.inputs.setHoverClick(this,
|
this.view.inputs.setHoverClick(this,
|
||||||
() => list.battleview.cursorOnShip(ship),
|
() => ship_buttons.cursorOnShip(ship),
|
||||||
() => list.battleview.cursorOffShip(ship),
|
() => ship_buttons.cursorOffShip(ship),
|
||||||
() => list.battleview.cursorClicked()
|
() => ship_buttons.cursorClicked()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,11 +59,9 @@ module TK.SpaceTac.UI {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move to a given location on screen
|
// Move to a given location on screen
|
||||||
moveTo(x: number, y: number, animate: boolean) {
|
moveTo(x: number, y: number, duration: number) {
|
||||||
if (animate) {
|
if (duration && (this.x != x || this.y != y)) {
|
||||||
var tween = this.game.tweens.create(this);
|
this.view.animations.addAnimation(this, {x: x, y: y}, duration, Phaser.Easing.Linear.None);
|
||||||
tween.to({ x: x, y: y });
|
|
||||||
tween.start();
|
|
||||||
} else {
|
} else {
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
|
|
|
@ -31,7 +31,7 @@ module TK.SpaceTac.UI {
|
||||||
filler.text(ship.getFullName(), 140, 0, { color: enemy ? "#cc0d00" : "#ffffff", size: 22, bold: true });
|
filler.text(ship.getFullName(), 140, 0, { color: enemy ? "#cc0d00" : "#ffffff", size: 22, bold: true });
|
||||||
|
|
||||||
if (ship.alive) {
|
if (ship.alive) {
|
||||||
let turns = this.battleview.battle.getTurnsBefore(ship);
|
let turns = this.battleview.battle.getPlayOrder(ship);
|
||||||
filler.text((turns == 0) ? "Playing" : ((turns == 1) ? "Plays next" : `Plays in ${turns} turns`), 140, 36, { color: "#cccccc", size: 18 });
|
filler.text((turns == 0) ? "Playing" : ((turns == 1) ? "Plays next" : `Plays in ${turns} turns`), 140, 36, { color: "#cccccc", size: 18 });
|
||||||
|
|
||||||
let hsp_builder = filler.styled({ color: "#eb4e4a", size: 20, center: true, vcenter: true, bold: true });
|
let hsp_builder = filler.styled({ color: "#eb4e4a", size: 20, center: true, vcenter: true, bold: true });
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/// <reference path="../TestGame.ts"/>
|
/// <reference path="../TestGame.ts"/>
|
||||||
|
|
||||||
module TK.SpaceTac.UI.Specs {
|
module TK.SpaceTac.UI.Specs {
|
||||||
describe("FleetCreationView", function () {
|
testing("FleetCreationView", test => {
|
||||||
let testgame = setupSingleView(() => [new FleetCreationView, []]);
|
let testgame = setupSingleView(() => [new FleetCreationView, []]);
|
||||||
|
|
||||||
it("has a basic equipment shop with infinite stock", function () {
|
test.case("has a basic equipment shop with infinite stock", function () {
|
||||||
let shop = testgame.view.infinite_shop;
|
let shop = testgame.view.infinite_shop;
|
||||||
let itemcount = shop.getStock().length;
|
let itemcount = shop.getStock().length;
|
||||||
expect(unique(shop.getStock().map(equ => equ.code)).length).toEqual(itemcount);
|
expect(unique(shop.getStock().map(equ => equ.code)).length).toEqual(itemcount);
|
||||||
|
@ -21,7 +21,7 @@ module TK.SpaceTac.UI.Specs {
|
||||||
expect(shop.getStock().length).toBe(itemcount);
|
expect(shop.getStock().length).toBe(itemcount);
|
||||||
})
|
})
|
||||||
|
|
||||||
async_it("validates the fleet creation", async function () {
|
test.acase("validates the fleet creation", async function () {
|
||||||
expect(testgame.ui.session.isFleetCreated()).toBe(false, "no fleet created");
|
expect(testgame.ui.session.isFleetCreated()).toBe(false, "no fleet created");
|
||||||
expect(testgame.ui.session.player.fleet.ships.length).toBe(0, "empty session fleet");
|
expect(testgame.ui.session.player.fleet.ships.length).toBe(0, "empty session fleet");
|
||||||
expect(testgame.view.dialogs_layer.children.length).toBe(0, "no dialogs");
|
expect(testgame.view.dialogs_layer.children.length).toBe(0, "no dialogs");
|
||||||
|
|
Loading…
Reference in a new issue