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
|
||||
* Add a voluntary retreat option
|
||||
* 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
|
||||
* Toggle bar/text display in power section of action bar
|
||||
* 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
|
||||
* Fix delay of shield/hull impact effects (should depend on weapon animation, and ship location)
|
||||
* Indicate visually the power gain of "end turn"
|
||||
* Add a turn count marker in the ship list
|
||||
|
||||
Ships models and equipments
|
||||
---------------------------
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit a530998523e8f8c7a37323d5dc047241f71f6a36
|
||||
Subproject commit 586788a4685a5b9a5cc8f4882f48f18c91997dc3
|
|
@ -63,54 +63,44 @@ module TK.SpaceTac {
|
|||
var fleet1 = new Fleet();
|
||||
var fleet2 = new Fleet();
|
||||
|
||||
var ship1 = new Ship(fleet1, "F1S1");
|
||||
var ship2 = new Ship(fleet1, "F1S2");
|
||||
var ship3 = new Ship(fleet2, "F2S1");
|
||||
var ship1 = new Ship(fleet1, "ship1");
|
||||
var ship2 = new Ship(fleet1, "ship2");
|
||||
var ship3 = new Ship(fleet2, "ship3");
|
||||
|
||||
var battle = new Battle(fleet1, fleet2);
|
||||
|
||||
// Check empty play_order case
|
||||
expect(battle.playing_ship).toBeNull();
|
||||
expect(battle.playing_ship_index).toBeNull();
|
||||
battle.advanceToNextShip();
|
||||
expect(battle.playing_ship).toBeNull();
|
||||
expect(battle.playing_ship_index).toBeNull();
|
||||
|
||||
// Force play order
|
||||
iforeach(battle.iships(), ship => ship.setAttribute("maneuvrability", 1));
|
||||
var gen = new SkewedRandomGenerator([0.1, 0.2, 0.0]);
|
||||
battle.throwInitiative(gen);
|
||||
|
||||
expect(battle.playing_ship).toBeNull();
|
||||
expect(battle.playing_ship_index).toBeNull();
|
||||
|
||||
battle.advanceToNextShip();
|
||||
|
||||
expect(battle.playing_ship).toBe(ship2);
|
||||
expect(battle.playing_ship_index).toBe(0);
|
||||
|
||||
battle.advanceToNextShip();
|
||||
|
||||
expect(battle.playing_ship).toBe(ship1);
|
||||
expect(battle.playing_ship_index).toBe(1);
|
||||
|
||||
battle.advanceToNextShip();
|
||||
|
||||
expect(battle.playing_ship).toBe(ship3);
|
||||
expect(battle.playing_ship_index).toBe(2);
|
||||
|
||||
battle.advanceToNextShip();
|
||||
|
||||
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();
|
||||
|
||||
battle.advanceToNextShip();
|
||||
expect(battle.playing_ship).toBe(ship3);
|
||||
|
||||
expect(battle.playing_ship).toBe(ship1);
|
||||
expect(battle.playing_ship_index).toBe(1);
|
||||
// Playing ship dies
|
||||
ship3.setDead();
|
||||
battle.advanceToNextShip();
|
||||
expect(battle.playing_ship).toBe(ship2);
|
||||
});
|
||||
|
||||
it("calls startTurn on ships", function () {
|
||||
|
@ -290,7 +280,7 @@ module TK.SpaceTac {
|
|||
expect(battle.canPlay(player)).toBe(false);
|
||||
|
||||
let ship = new Ship();
|
||||
battle.playing_ship = ship;
|
||||
TestTools.setShipPlaying(battle, ship);
|
||||
|
||||
expect(battle.canPlay(player)).toBe(false);
|
||||
|
||||
|
@ -306,28 +296,28 @@ module TK.SpaceTac {
|
|||
battle.advanceToNextShip();
|
||||
|
||||
expect(battle.playing_ship).toBe(battle.play_order[0]);
|
||||
expect(battle.getTurnsBefore(battle.play_order[0])).toBe(0);
|
||||
expect(battle.getTurnsBefore(battle.play_order[1])).toBe(1);
|
||||
expect(battle.getTurnsBefore(battle.play_order[2])).toBe(2);
|
||||
expect(battle.getPlayOrder(battle.play_order[0])).toBe(0);
|
||||
expect(battle.getPlayOrder(battle.play_order[1])).toBe(1);
|
||||
expect(battle.getPlayOrder(battle.play_order[2])).toBe(2);
|
||||
|
||||
battle.advanceToNextShip();
|
||||
|
||||
expect(battle.playing_ship).toBe(battle.play_order[1]);
|
||||
expect(battle.getTurnsBefore(battle.play_order[0])).toBe(2);
|
||||
expect(battle.getTurnsBefore(battle.play_order[1])).toBe(0);
|
||||
expect(battle.getTurnsBefore(battle.play_order[2])).toBe(1);
|
||||
expect(battle.getPlayOrder(battle.play_order[0])).toBe(2);
|
||||
expect(battle.getPlayOrder(battle.play_order[1])).toBe(0);
|
||||
expect(battle.getPlayOrder(battle.play_order[2])).toBe(1);
|
||||
|
||||
battle.advanceToNextShip();
|
||||
|
||||
expect(battle.getTurnsBefore(battle.play_order[0])).toBe(1);
|
||||
expect(battle.getTurnsBefore(battle.play_order[1])).toBe(2);
|
||||
expect(battle.getTurnsBefore(battle.play_order[2])).toBe(0);
|
||||
expect(battle.getPlayOrder(battle.play_order[0])).toBe(1);
|
||||
expect(battle.getPlayOrder(battle.play_order[1])).toBe(2);
|
||||
expect(battle.getPlayOrder(battle.play_order[2])).toBe(0);
|
||||
|
||||
battle.advanceToNextShip();
|
||||
|
||||
expect(battle.getTurnsBefore(battle.play_order[0])).toBe(0);
|
||||
expect(battle.getTurnsBefore(battle.play_order[1])).toBe(1);
|
||||
expect(battle.getTurnsBefore(battle.play_order[2])).toBe(2);
|
||||
expect(battle.getPlayOrder(battle.play_order[0])).toBe(0);
|
||||
expect(battle.getPlayOrder(battle.play_order[1])).toBe(1);
|
||||
expect(battle.getPlayOrder(battle.play_order[2])).toBe(2);
|
||||
});
|
||||
|
||||
it("lists area effects", function () {
|
||||
|
|
|
@ -19,15 +19,15 @@ module TK.SpaceTac {
|
|||
// List of fleets engaged in battle
|
||||
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_index = -1
|
||||
|
||||
// Current turn
|
||||
turn: number
|
||||
|
||||
// Current ship whose turn it is to play
|
||||
playing_ship_index: number | null
|
||||
playing_ship: Ship | null
|
||||
// Current battle "cycle" (one cycle is one turn done for all ships in the play order)
|
||||
cycle: number
|
||||
|
||||
// List of deployed drones
|
||||
drones: Drone[] = []
|
||||
|
@ -47,9 +47,8 @@ module TK.SpaceTac {
|
|||
// Create a battle between two fleets
|
||||
constructor(fleet1 = new Fleet(), fleet2 = new Fleet(), width = 1808, height = 948) {
|
||||
this.fleets = [fleet1, fleet2];
|
||||
this.ships = new RObjectContainer(fleet1.ships.concat(fleet2.ships));
|
||||
this.play_order = [];
|
||||
this.playing_ship_index = null;
|
||||
this.playing_ship = null;
|
||||
this.ended = false;
|
||||
this.width = width;
|
||||
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 {
|
||||
return this.play_order.length;
|
||||
get playing_ship(): Ship | null {
|
||||
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 {
|
||||
let pos = this.play_order.indexOf(ship) - (this.playing_ship_index || 0);
|
||||
if (pos < 0) {
|
||||
pos += this.play_order.length;
|
||||
}
|
||||
return pos;
|
||||
getShip(id: RObjectId): Ship | null {
|
||||
return this.ships.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -150,6 +145,42 @@ module TK.SpaceTac {
|
|||
return (ship2.play_priority - ship1.play_priority);
|
||||
});
|
||||
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
|
||||
|
@ -195,7 +226,7 @@ module TK.SpaceTac {
|
|||
}
|
||||
|
||||
// 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]);
|
||||
}
|
||||
|
||||
|
@ -228,10 +259,10 @@ module TK.SpaceTac {
|
|||
// If at the end of the play order, next turn will start automatically
|
||||
// Member 'play_order' must be defined before calling this function
|
||||
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) {
|
||||
this.playing_ship.endTurn();
|
||||
if (previous_ship && previous_ship.playing) {
|
||||
previous_ship.endTurn();
|
||||
}
|
||||
|
||||
if (this.checkEndBattle(log)) {
|
||||
|
@ -240,21 +271,14 @@ module TK.SpaceTac {
|
|||
|
||||
this.drones.forEach(drone => drone.activate());
|
||||
|
||||
if (this.play_order.length === 0) {
|
||||
this.playing_ship_index = null;
|
||||
this.playing_ship = null;
|
||||
} 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];
|
||||
this.play_index += 1;
|
||||
if (this.play_index >= this.play_order.length) {
|
||||
this.play_index = 0;
|
||||
}
|
||||
|
||||
if (this.playing_ship) {
|
||||
if (this.playing_ship_index == 0) {
|
||||
this.turn += 1;
|
||||
if (this.play_index == 0) {
|
||||
this.cycle += 1;
|
||||
}
|
||||
this.playing_ship.startTurn();
|
||||
}
|
||||
|
@ -288,7 +312,7 @@ module TK.SpaceTac {
|
|||
// This will not add any event to the battle log
|
||||
start(): void {
|
||||
this.ended = false;
|
||||
this.turn = 0;
|
||||
this.cycle = 0;
|
||||
this.placeShips();
|
||||
this.stats.onBattleStart(this.fleets[0], this.fleets[1]);
|
||||
this.throwInitiative();
|
||||
|
@ -324,7 +348,7 @@ module TK.SpaceTac {
|
|||
// Indicate emergency stasis
|
||||
this.play_order.forEach(ship => {
|
||||
if (!ship.alive) {
|
||||
let event = new DeathEvent(ship);
|
||||
let event = new DeathEvent(this, ship);
|
||||
event.initial = true;
|
||||
result.push(event);
|
||||
}
|
||||
|
@ -347,6 +371,18 @@ module TK.SpaceTac {
|
|||
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
|
||||
*
|
||||
|
|
|
@ -22,12 +22,13 @@ module TK.SpaceTac.Specs {
|
|||
|
||||
it("adds an equipment", function () {
|
||||
let battle = new Battle();
|
||||
battle.playing_ship = new Ship();
|
||||
battle.playing_ship.upgradeSkill("skill_materials");
|
||||
let ship = new Ship();
|
||||
TestTools.setShipPlaying(battle, ship);
|
||||
ship.upgradeSkill("skill_materials");
|
||||
|
||||
expect(battle.playing_ship.listEquipment()).toEqual([]);
|
||||
expect(ship.listEquipment()).toEqual([]);
|
||||
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 () {
|
||||
let fleet = new Fleet();
|
||||
let battle = new Battle();
|
||||
let fleet = battle.fleets[0];
|
||||
expect(fleet.isAlive()).toBe(false);
|
||||
|
||||
let ship1 = fleet.addShip();
|
||||
|
|
|
@ -61,6 +61,9 @@ module TK.SpaceTac {
|
|||
}
|
||||
add(this.ships, ship);
|
||||
ship.fleet = this;
|
||||
if (this.battle) {
|
||||
this.battle.ships.add(ship);
|
||||
}
|
||||
return ship;
|
||||
}
|
||||
|
||||
|
|
|
@ -236,7 +236,7 @@ module TK.SpaceTac.Specs {
|
|||
expect(action.activated).toBe(false);
|
||||
|
||||
let battle = new Battle(ship.fleet);
|
||||
battle.playing_ship = ship;
|
||||
TestTools.setShipPlaying(battle, ship);
|
||||
|
||||
ship.startTurn();
|
||||
expect(action.activated).toBe(false);
|
||||
|
@ -273,7 +273,7 @@ module TK.SpaceTac.Specs {
|
|||
|
||||
let shield = ship1.addSlot(SlotType.Shield).attach(new Equipment(SlotType.Shield));
|
||||
shield.action = new ToggleAction(shield, 0, 15, [new AttributeEffect("shield_capacity", 5)]);
|
||||
battle.playing_ship = ship1;
|
||||
TestTools.setShipPlaying(battle, ship1);
|
||||
shield.action.apply(ship1);
|
||||
|
||||
expect(ship1.getAttribute("shield_capacity")).toBe(5);
|
||||
|
@ -325,15 +325,15 @@ module TK.SpaceTac.Specs {
|
|||
ship.addDamage(5, 0);
|
||||
|
||||
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[1].code).toEqual("damage");
|
||||
expect(battle.log.events[2].code).toEqual("activeeffects");
|
||||
expect(battle.log.events[3].code).toEqual("death");
|
||||
expect(battle.log.events[2].code).toEqual("death");
|
||||
});
|
||||
|
||||
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(false)).toBe(true);
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
/// <reference path="../common/RObject.ts" />
|
||||
|
||||
module TK.SpaceTac {
|
||||
/**
|
||||
* A single ship in a fleet
|
||||
*/
|
||||
export class Ship {
|
||||
export class Ship extends RObject {
|
||||
// Fleet this ship is a member of
|
||||
fleet: Fleet
|
||||
|
||||
|
@ -56,6 +58,8 @@ module TK.SpaceTac {
|
|||
|
||||
// Create a new ship inside a fleet
|
||||
constructor(fleet: Fleet | null = null, name = "unnamed", model = new ShipModel("default", "Default", 1, 0, false, 0)) {
|
||||
super();
|
||||
|
||||
this.fleet = fleet || new Fleet();
|
||||
this.name = name;
|
||||
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
|
||||
*/
|
||||
setDead(log: boolean = true): void {
|
||||
this.alive = false;
|
||||
this.values.hull.set(0);
|
||||
this.values.shield.set(0);
|
||||
this.values.power.set(0);
|
||||
|
||||
this.sticky_effects = [];
|
||||
this.setActiveEffectsChanged();
|
||||
|
||||
if (log) {
|
||||
this.addBattleEvent(new DeathEvent(this));
|
||||
setDead(): void {
|
||||
let battle = this.getBattle();
|
||||
if (battle) {
|
||||
let events = this.getDeathEvents(battle);
|
||||
battle.applyEvents(events);
|
||||
} else {
|
||||
console.error("Cannot set ship dead outside of battle", this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -500,7 +533,7 @@ module TK.SpaceTac {
|
|||
|
||||
if (this.values.hull.get() === 0) {
|
||||
// Ship is dead
|
||||
this.setDead(log);
|
||||
this.setDead();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -53,6 +53,13 @@ module TK.SpaceTac {
|
|||
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
|
||||
static setShipAP(ship: Ship, points: number, recovery: number = 0): void {
|
||||
var equipment = this.getOrGenEquipment(ship, SlotType.Power, new Equipments.NuclearReactor());
|
||||
|
|
|
@ -26,7 +26,7 @@ module TK.SpaceTac {
|
|||
let battle = new Battle();
|
||||
let ship = battle.fleets[0].addShip();
|
||||
ship.setArenaPosition(0, 0);
|
||||
battle.playing_ship = ship;
|
||||
TestTools.setShipPlaying(battle, ship);
|
||||
TestTools.setShipAP(ship, 3);
|
||||
let equipment = new Equipment(SlotType.Weapon, "testdrone");
|
||||
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 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]));
|
||||
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 () {
|
||||
var ship = new Ship();
|
||||
var battle = new Battle(ship.fleet);
|
||||
battle.playing_ship = ship;
|
||||
TestTools.setShipPlaying(battle, ship);
|
||||
ship.values.power.setMaximal(20);
|
||||
ship.values.power.set(6);
|
||||
ship.arena_x = 0;
|
||||
|
@ -45,7 +45,7 @@ module TK.SpaceTac {
|
|||
ship.arena_y = 0;
|
||||
var engine = new Equipment();
|
||||
var action = new MoveAction(engine, 1);
|
||||
battle.playing_ship = ship;
|
||||
TestTools.setShipPlaying(battle, ship);
|
||||
|
||||
spyOn(console, "warn").and.stub();
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ module TK.SpaceTac {
|
|||
|
||||
let battle = new Battle(fleet);
|
||||
battle.play_order = [ship, ship1, ship2, ship3];
|
||||
battle.playing_ship = ship;
|
||||
TestTools.setShipPlaying(battle, ship);
|
||||
fleet.setBattle(battle);
|
||||
|
||||
action.apply(ship, Target.newFromLocation(50, 50));
|
||||
|
|
|
@ -78,7 +78,7 @@ module TK.SpaceTac {
|
|||
});
|
||||
|
||||
// Run battle
|
||||
while (!battle.ended && battle.turn < 100) {
|
||||
while (!battle.ended && battle.cycle < 100) {
|
||||
if (this.stopped) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ module TK.SpaceTac.Specs {
|
|||
it("applies the highest evaluated maneuver", function () {
|
||||
let battle = new Battle();
|
||||
let ship = battle.fleets[0].addShip();
|
||||
battle.playing_ship = ship;
|
||||
TestTools.setShipPlaying(battle, ship);
|
||||
ship.playing = true;
|
||||
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"));
|
||||
|
||||
TestTools.setShipAP(ship0a, 10);
|
||||
battle.playing_ship = ship0a;
|
||||
TestTools.setShipPlaying(battle, ship0a);
|
||||
|
||||
let result = imaterialize(TacticalAIHelpers.produceDirectShots(ship0a, battle));
|
||||
expect(result.length).toBe(0);
|
||||
|
@ -30,7 +30,7 @@ module TK.SpaceTac.Specs {
|
|||
let ship = battle.fleets[0].addShip();
|
||||
|
||||
TestTools.setShipAP(ship, 10);
|
||||
battle.playing_ship = ship;
|
||||
TestTools.setShipPlaying(battle, ship);
|
||||
|
||||
let result = imaterialize(TacticalAIHelpers.produceRandomMoves(ship, battle, 2, 1));
|
||||
expect(result.length).toBe(0);
|
||||
|
@ -52,7 +52,7 @@ module TK.SpaceTac.Specs {
|
|||
let weapon = TestTools.addWeapon(ship, 50, 1, 1000, 105);
|
||||
|
||||
TestTools.setShipAP(ship, 10);
|
||||
battle.playing_ship = ship;
|
||||
TestTools.setShipPlaying(battle, ship);
|
||||
|
||||
let result = imaterialize(TacticalAIHelpers.produceInterestingBlastShots(ship, battle));
|
||||
expect(result.length).toBe(0);
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
module TK.SpaceTac.Specs {
|
||||
describe("DamageEffect", 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);
|
||||
let hull = ship.listEquipment(SlotType.Hull)[0];
|
||||
|
|
|
@ -40,8 +40,7 @@ module TK.SpaceTac.Equipments {
|
|||
ship1.setArenaPosition(0, 0);
|
||||
ship2.setArenaPosition(100, 0);
|
||||
ship3.setArenaPosition(800, 0);
|
||||
battle.playing_ship = ship1;
|
||||
ship1.playing = true;
|
||||
TestTools.setShipPlaying(battle, ship1);
|
||||
expect(ship1.getAvailableActions()).toEqual([action, new EndTurnAction()]);
|
||||
|
||||
TestTools.setShipHP(ship1, 100, 0);
|
||||
|
|
|
@ -38,8 +38,7 @@ module TK.SpaceTac.Equipments {
|
|||
|
||||
let battle = new Battle();
|
||||
let ship = battle.fleets[0].addShip();
|
||||
battle.playing_ship = ship;
|
||||
battle.play_order = [ship];
|
||||
TestTools.setShipPlaying(battle, ship);
|
||||
TestTools.setShipAP(ship, 10);
|
||||
let result = nn(equipment.action).apply(ship, new Target(5, 5, null));
|
||||
expect(result).toBe(true);
|
||||
|
|
|
@ -28,7 +28,16 @@ module TK.SpaceTac {
|
|||
*
|
||||
* 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"/>
|
||||
|
||||
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 {
|
||||
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);
|
||||
|
||||
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 {
|
||||
describe("ValueChangeEvent", function () {
|
||||
it("get reverse event", function () {
|
||||
testing("ValueChangeEvent", test => {
|
||||
test.case("get reverse event", check => {
|
||||
let ship = new Ship();
|
||||
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
|
||||
*/
|
||||
export class ValueChangeEvent extends BaseLogShipEvent {
|
||||
// Ship ID
|
||||
ship_id: RObjectId
|
||||
|
||||
// Saved version of the current value
|
||||
value: ShipValue;
|
||||
value: ShipValue
|
||||
|
||||
// Value variation
|
||||
diff: number;
|
||||
diff: number
|
||||
|
||||
constructor(ship: Ship, value: ShipValue, diff: number) {
|
||||
super("value", ship);
|
||||
|
||||
this.ship_id = ship.id;
|
||||
this.value = copy(value);
|
||||
this.diff = diff;
|
||||
}
|
||||
|
@ -23,5 +27,14 @@ module TK.SpaceTac {
|
|||
value.set(value.get() - 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 {
|
||||
describe("Connection", function () {
|
||||
async_it("finds an unused token", async function () {
|
||||
testing("Connection", test => {
|
||||
test.acase("finds an unused token", async check => {
|
||||
let storage = new FakeRemoteStorage();
|
||||
let connection = new Connection("test", storage);
|
||||
|
||||
|
@ -15,7 +15,7 @@ module TK.SpaceTac.Multi.Specs {
|
|||
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 serializer = new Serializer(TK.SpaceTac);
|
||||
let storage = new FakeRemoteStorage();
|
||||
|
@ -42,7 +42,7 @@ module TK.SpaceTac.Multi.Specs {
|
|||
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 connection = new Connection("test", storage);
|
||||
|
||||
|
@ -57,7 +57,7 @@ module TK.SpaceTac.Multi.Specs {
|
|||
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 storage = new FakeRemoteStorage();
|
||||
let connection = new Connection("test", storage);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
module TK.SpaceTac.Multi.Specs {
|
||||
describe("Exchange", function () {
|
||||
testing("Exchange", test => {
|
||||
function newExchange(token: string, storage = new FakeRemoteStorage()): [FakeRemoteStorage, Exchange, Exchange] {
|
||||
let connection = new Connection("test", storage);
|
||||
|
||||
|
@ -17,7 +17,7 @@ module TK.SpaceTac.Multi.Specs {
|
|||
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");
|
||||
spyOn(peer1, "getNextId").and.returnValues("1A", "1B", "1C");
|
||||
spyOn(peer2, "getNextId").and.returnValues("2A", "2B", "2C");
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
module TK.SpaceTac.Multi.Specs {
|
||||
describe("FakeRemoteStorage", function () {
|
||||
async_it("can fetch a single record", async function () {
|
||||
testing("FakeRemoteStorage", test => {
|
||||
test.acase("can fetch a single record", async function () {
|
||||
let storage = new FakeRemoteStorage();
|
||||
|
||||
let result = await storage.find("test", { key: 5 });
|
||||
|
@ -21,7 +21,7 @@ module TK.SpaceTac.Multi.Specs {
|
|||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
async_it("inserts or updates objects", async function () {
|
||||
test.acase("inserts or updates objects", async function () {
|
||||
let storage = new FakeRemoteStorage();
|
||||
|
||||
let result = await storage.search("test", { key: 5 });
|
||||
|
|
|
@ -241,17 +241,21 @@ module TK.SpaceTac.UI {
|
|||
*/
|
||||
getImageInfo(name: string): { key: string, frame: number } {
|
||||
// TODO Cache
|
||||
let i = 1;
|
||||
while (this.game.cache.checkImageKey(`atlas-${i}`)) {
|
||||
let data = this.game.cache.getFrameData(`atlas-${i}`);
|
||||
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 };
|
||||
if (this.game.cache.checkImageKey(name)) {
|
||||
return { key: name, frame: 0 };
|
||||
} else {
|
||||
let i = 1;
|
||||
while (this.game.cache.checkImageKey(`atlas-${i}`)) {
|
||||
let data = this.game.cache.getFrameData(`atlas-${i}`);
|
||||
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();
|
||||
|
||||
// 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.moveTo(ship.arena_x, ship.arena_y, ship.arena_angle);
|
||||
} else {
|
||||
|
@ -145,7 +145,7 @@ module TK.SpaceTac.UI {
|
|||
if (event.new_ship === this.ship) {
|
||||
this.play_order.text = "-";
|
||||
} 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;
|
||||
|
|
|
@ -1,8 +1,19 @@
|
|||
/// <reference path="../BaseView.ts"/>
|
||||
|
||||
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
|
||||
battle: Battle
|
||||
|
||||
|
@ -102,8 +113,8 @@ module TK.SpaceTac.UI {
|
|||
// Add UI elements
|
||||
this.action_bar = new ActionBar(this);
|
||||
this.action_bar.position.set(0, this.getHeight() - 132);
|
||||
this.ship_list = new ShipList(this);
|
||||
this.ship_list.position.set(this.getWidth() - 112, 0);
|
||||
this.ship_list = new ShipList(this, this.battle, this.player, this.toggle_tactical_mode, this,
|
||||
this.layer_borders, this.getWidth() - 112, 0);
|
||||
this.ship_tooltip = new ShipTooltip(this);
|
||||
this.character_sheet = new CharacterSheet(this, -this.getWidth());
|
||||
this.layer_sheets.add(this.character_sheet);
|
||||
|
@ -179,7 +190,7 @@ module TK.SpaceTac.UI {
|
|||
numberPressed(num: number): void {
|
||||
if (this.interacting) {
|
||||
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) {
|
||||
this.targetting.setTarget(Target.newFromShip(ship));
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ module TK.SpaceTac.UI.Specs {
|
|||
}
|
||||
|
||||
apply(battle: Battle) {
|
||||
battle.turn += this.diff;
|
||||
battle.cycle += this.diff;
|
||||
}
|
||||
|
||||
getReverse(): BaseBattleEvent {
|
||||
|
@ -31,42 +31,42 @@ module TK.SpaceTac.UI.Specs {
|
|||
event.apply(battle);
|
||||
return 0;
|
||||
});
|
||||
expect(battle.turn).toBe(1);
|
||||
expect(battle.cycle).toBe(1);
|
||||
expect(processor.atStart()).toBe(true);
|
||||
expect(processor.atEnd()).toBe(true);
|
||||
|
||||
processor.stepForward();
|
||||
expect(battle.turn).toBe(1);
|
||||
expect(battle.cycle).toBe(1);
|
||||
expect(processor.atStart()).toBe(true);
|
||||
expect(processor.atEnd()).toBe(true);
|
||||
|
||||
battle.log.add(new FakeEvent());
|
||||
expect(battle.turn).toBe(1);
|
||||
expect(battle.cycle).toBe(1);
|
||||
expect(processor.atStart()).toBe(true);
|
||||
expect(processor.atEnd()).toBe(false);
|
||||
|
||||
processor.stepForward();
|
||||
expect(battle.turn).toBe(2);
|
||||
expect(battle.cycle).toBe(2);
|
||||
expect(processor.atStart()).toBe(false);
|
||||
expect(processor.atEnd()).toBe(true);
|
||||
|
||||
processor.stepForward();
|
||||
expect(battle.turn).toBe(2);
|
||||
expect(battle.cycle).toBe(2);
|
||||
expect(processor.atStart()).toBe(false);
|
||||
expect(processor.atEnd()).toBe(true);
|
||||
|
||||
processor.stepBackward();
|
||||
expect(battle.turn).toBe(1);
|
||||
expect(battle.cycle).toBe(1);
|
||||
expect(processor.atStart()).toBe(true);
|
||||
expect(processor.atEnd()).toBe(false);
|
||||
|
||||
processor.stepBackward();
|
||||
expect(battle.turn).toBe(1);
|
||||
expect(battle.cycle).toBe(1);
|
||||
expect(processor.atStart()).toBe(true);
|
||||
expect(processor.atEnd()).toBe(false);
|
||||
|
||||
processor.stepForward();
|
||||
expect(battle.turn).toBe(2);
|
||||
expect(battle.cycle).toBe(2);
|
||||
expect(processor.atStart()).toBe(false);
|
||||
expect(processor.atEnd()).toBe(true);
|
||||
})
|
||||
|
|
|
@ -288,7 +288,7 @@ module TK.SpaceTac.UI {
|
|||
private processShipChangeEvent(event: ShipChangeEvent): number {
|
||||
this.current_ship = 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) {
|
||||
this.view.audio.playOnce("battle-ship-change");
|
||||
}
|
||||
|
@ -306,13 +306,19 @@ module TK.SpaceTac.UI {
|
|||
|
||||
// A ship died
|
||||
private processDeathEvent(event: DeathEvent): number {
|
||||
if (this.view.ship_hovered === event.ship) {
|
||||
this.view.setShipHovered(null);
|
||||
}
|
||||
this.view.arena.markAsDead(event.ship);
|
||||
this.view.ship_list.markAsDead(event.ship);
|
||||
let ship = this.battle.getShip(event.ship_id);
|
||||
|
||||
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
|
||||
|
|
|
@ -1,26 +1,65 @@
|
|||
/// <reference path="../TestGame.ts"/>
|
||||
|
||||
module TK.SpaceTac.UI.Specs {
|
||||
describe("ShipList", function () {
|
||||
let testgame = setupBattleview();
|
||||
testing("ShipList", test => {
|
||||
let testgame = setupEmptyView();
|
||||
|
||||
it("handles play position of ships", function () {
|
||||
let battleview = testgame.view;
|
||||
var list = battleview.ship_list;
|
||||
function createList(): ShipList {
|
||||
let view = testgame.view;
|
||||
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);
|
||||
expect(list.children.length).toBe(11);
|
||||
test.case("handles play position of ships", check => {
|
||||
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);
|
||||
expect(list.findPlayPosition(battleview.battle.play_order[1])).toBe(1);
|
||||
expect(list.findPlayPosition(battleview.battle.play_order[2])).toBe(2);
|
||||
battle.fleets[0].addShip();
|
||||
list.setShipsFromBattle(battle, false);
|
||||
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();
|
||||
battleview.battle.advanceToNextShip();
|
||||
battle.throwInitiative();
|
||||
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);
|
||||
expect(list.findPlayPosition(battleview.battle.play_order[1])).toBe(0);
|
||||
expect(list.findPlayPosition(battleview.battle.play_order[2])).toBe(1);
|
||||
battle.fleets[1].addShip();
|
||||
battle.throwInitiative();
|
||||
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 {
|
||||
// Bar with all playing ships, by play order
|
||||
export class ShipList extends Phaser.Image {
|
||||
// Link to the parent battleview
|
||||
battleview: BattleView;
|
||||
/**
|
||||
* Side bar with all playing ships, sorted by play order
|
||||
*/
|
||||
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
|
||||
ships_container: Phaser.Group;
|
||||
ships: ShipListItem[];
|
||||
|
||||
// Playing ship
|
||||
playing: ShipListItem | null;
|
||||
items: ShipListItem[]
|
||||
|
||||
// Hovered ship
|
||||
hovered: ShipListItem | null;
|
||||
hovered: ShipListItem | null
|
||||
|
||||
// Info button
|
||||
info_button: Phaser.Button;
|
||||
info_button: Phaser.Button
|
||||
|
||||
// Create an empty action bar
|
||||
constructor(battleview: BattleView) {
|
||||
super(battleview.game, 0, 0, "battle-shiplist-background");
|
||||
constructor(view: BaseView, battle: Battle, player: Player, tactical_mode: Toggle, ship_buttons: IShipButton, parent?: UIContainer, x = 0, y = 0) {
|
||||
let builder = new UIBuilder(view, parent);
|
||||
this.container = builder.image("battle-shiplist-background", x, y);
|
||||
|
||||
this.battleview = battleview;
|
||||
this.ships = [];
|
||||
this.playing = null;
|
||||
this.view = view;
|
||||
// TODO Should use an UI game state, not the actual game state
|
||||
this.battle = battle;
|
||||
this.player = player;
|
||||
this.ship_buttons = ship_buttons;
|
||||
|
||||
this.items = [];
|
||||
this.hovered = null;
|
||||
|
||||
this.info_button = new Phaser.Button(this.game, 0, 0, "battle-shiplist-info-button");
|
||||
this.battleview.inputs.setHoverClick(this.info_button,
|
||||
() => this.battleview.toggle_tactical_mode.manipulate("button")(true),
|
||||
() => this.battleview.toggle_tactical_mode.manipulate("button")(false),
|
||||
this.info_button = new Phaser.Button(view.game, 0, 0, "battle-shiplist-info-button");
|
||||
this.view.inputs.setHoverClick(this.info_button,
|
||||
() => tactical_mode.manipulate("shiplist")(true),
|
||||
() => tactical_mode.manipulate("shiplist")(false),
|
||||
() => null);
|
||||
this.addChild(this.info_button);
|
||||
this.container.addChild(this.info_button);
|
||||
|
||||
battleview.layer_borders.add(this);
|
||||
|
||||
if (battleview.battle) {
|
||||
this.setShipsFromBattle(battleview.battle);
|
||||
}
|
||||
this.setShipsFromBattle(battle);
|
||||
}
|
||||
|
||||
// Clear the action icons
|
||||
/**
|
||||
* Clear all ship cards
|
||||
*/
|
||||
clearAll(): void {
|
||||
this.ships.forEach((ship: ShipListItem) => {
|
||||
ship.destroy();
|
||||
});
|
||||
this.ships = [];
|
||||
this.items.forEach(ship => ship.destroy());
|
||||
this.items = [];
|
||||
}
|
||||
|
||||
// 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();
|
||||
battle.play_order.forEach((ship: Ship) => {
|
||||
this.addShip(ship);
|
||||
}, this);
|
||||
this.updateItemsLocation();
|
||||
iforeach(battle.iships(true), ship => this.addShip(ship));
|
||||
this.refresh(animate);
|
||||
}
|
||||
|
||||
// Add a ship icon
|
||||
/**
|
||||
* Add a ship card
|
||||
*/
|
||||
addShip(ship: Ship): ShipListItem {
|
||||
var owned = ship.getPlayer() === this.battleview.player;
|
||||
var result = new ShipListItem(this, 200, this.height / 2, ship, owned);
|
||||
this.ships.push(result);
|
||||
this.addChild(result);
|
||||
var owned = ship.getPlayer() === this.player;
|
||||
var result = new ShipListItem(this, 200, this.container.height / 2, ship, owned, this.ship_buttons);
|
||||
this.items.push(result);
|
||||
this.container.addChild(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 {
|
||||
var found: ShipListItem | null = null;
|
||||
this.ships.forEach((item: ShipListItem) => {
|
||||
if (item.ship === ship) {
|
||||
found = item;
|
||||
}
|
||||
});
|
||||
return found;
|
||||
return first(this.items, item => item.ship == ship);
|
||||
}
|
||||
|
||||
// Find the play position in play_order for a given ship (0 is currently playing)
|
||||
findPlayPosition(ship: Ship): number {
|
||||
var battle = this.battleview.battle;
|
||||
var idx = battle.play_order.indexOf(ship);
|
||||
var diff = idx - (battle.playing_ship_index || 0);
|
||||
if (diff < 0) {
|
||||
diff += battle.play_order.length;
|
||||
}
|
||||
return diff;
|
||||
}
|
||||
|
||||
// Update the locations of all items
|
||||
updateItemsLocation(animate: boolean = true): void {
|
||||
this.ships.forEach((item: ShipListItem) => {
|
||||
var position = this.findPlayPosition(item.ship);
|
||||
if (position === 0) {
|
||||
item.moveTo(-18, 962, animate);
|
||||
/**
|
||||
* Update the locations of all items
|
||||
*/
|
||||
refresh(animate = true): void {
|
||||
this.items.forEach(item => {
|
||||
if (item.ship.alive) {
|
||||
let position = this.battle.getPlayOrder(item.ship);
|
||||
if (position < 0) {
|
||||
item.visible = false;
|
||||
} else {
|
||||
if (position == 0) {
|
||||
item.moveTo(-18, 962, animate ? 1000 : 0);
|
||||
} else {
|
||||
item.moveTo(2, 942 - position * 99, animate ? 1000 : 0);
|
||||
}
|
||||
item.visible = true;
|
||||
this.container.setChildIndex(item, position);
|
||||
}
|
||||
} 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 {
|
||||
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
|
||||
/**
|
||||
* Set the currently hovered ship
|
||||
*/
|
||||
setHovered(ship: Ship | null): void {
|
||||
if (this.hovered) {
|
||||
this.hovered.setHovered(false);
|
||||
|
|
|
@ -2,11 +2,14 @@ module TK.SpaceTac.UI {
|
|||
// One item in a ship list (used in BattleView)
|
||||
export class ShipListItem extends Phaser.Button {
|
||||
// Reference to the view
|
||||
view: BattleView
|
||||
view: BaseView
|
||||
|
||||
// Reference to the ship game object
|
||||
ship: Ship
|
||||
|
||||
// Callbacks to act as buttons
|
||||
ship_buttons: IShipButton
|
||||
|
||||
// Player indicator
|
||||
player_indicator: Phaser.Image
|
||||
|
||||
|
@ -20,9 +23,9 @@ module TK.SpaceTac.UI {
|
|||
hover_indicator: Phaser.Image
|
||||
|
||||
// Create a ship button for the battle ship list
|
||||
constructor(list: ShipList, x: number, y: number, ship: Ship, owned: boolean) {
|
||||
super(list.battleview.game, x, y, "battle-shiplist-item-background");
|
||||
this.view = list.battleview;
|
||||
constructor(list: ShipList, x: number, y: number, ship: Ship, owned: boolean, ship_buttons: IShipButton) {
|
||||
super(list.view.game, x, y, "battle-shiplist-item-background");
|
||||
this.view = list.view;
|
||||
|
||||
this.ship = ship;
|
||||
|
||||
|
@ -44,9 +47,9 @@ module TK.SpaceTac.UI {
|
|||
this.addChild(this.hover_indicator);
|
||||
|
||||
this.view.inputs.setHoverClick(this,
|
||||
() => list.battleview.cursorOnShip(ship),
|
||||
() => list.battleview.cursorOffShip(ship),
|
||||
() => list.battleview.cursorClicked()
|
||||
() => ship_buttons.cursorOnShip(ship),
|
||||
() => ship_buttons.cursorOffShip(ship),
|
||||
() => ship_buttons.cursorClicked()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -56,11 +59,9 @@ module TK.SpaceTac.UI {
|
|||
}
|
||||
|
||||
// Move to a given location on screen
|
||||
moveTo(x: number, y: number, animate: boolean) {
|
||||
if (animate) {
|
||||
var tween = this.game.tweens.create(this);
|
||||
tween.to({ x: x, y: y });
|
||||
tween.start();
|
||||
moveTo(x: number, y: number, duration: number) {
|
||||
if (duration && (this.x != x || this.y != y)) {
|
||||
this.view.animations.addAnimation(this, {x: x, y: y}, duration, Phaser.Easing.Linear.None);
|
||||
} else {
|
||||
this.x = x;
|
||||
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 });
|
||||
|
||||
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 });
|
||||
|
||||
let hsp_builder = filler.styled({ color: "#eb4e4a", size: 20, center: true, vcenter: true, bold: true });
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/// <reference path="../TestGame.ts"/>
|
||||
|
||||
module TK.SpaceTac.UI.Specs {
|
||||
describe("FleetCreationView", function () {
|
||||
testing("FleetCreationView", test => {
|
||||
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 itemcount = shop.getStock().length;
|
||||
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);
|
||||
})
|
||||
|
||||
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.player.fleet.ships.length).toBe(0, "empty session fleet");
|
||||
expect(testgame.view.dialogs_layer.children.length).toBe(0, "no dialogs");
|
||||
|
|
Loading…
Reference in a new issue