Some refactoring needed for future work on battle log
This commit is contained in:
parent
be6f00d0e9
commit
83807beb20
2
TODO
2
TODO
|
@ -1,3 +1,4 @@
|
|||
* New battle internal flow: any game state change should be done through revertable events
|
||||
* UI: use a common component class, and a layer abstraction
|
||||
* Character sheet: add initial character creation
|
||||
* Character sheet: disable interaction during battle (except for loot screen)
|
||||
|
@ -23,7 +24,6 @@
|
|||
* Arena: fix effects originating from real ship location instead of current sprite (when AI fires then moves)
|
||||
* Arena: add engine trail
|
||||
* Arena: draw move exclusion circles and border (in move targetting only)
|
||||
* Remove "initial events" injection
|
||||
* Fix capacity limit effect not refreshing associated value (for example, on "limit power capacity to 3", potential "power" value change is not broadcast)
|
||||
* Actions: show power usage/recovery in power bar, on action hover
|
||||
* Actions: fix targetting not resetting when using keyboard shortcuts
|
||||
|
|
|
@ -278,11 +278,9 @@ module TS.SpaceTac {
|
|||
|
||||
// check initial log fill
|
||||
battle.drones = [drone];
|
||||
battle.log.events = [];
|
||||
battle.injectInitialEvents();
|
||||
let expected = new DroneDeployedEvent(drone);
|
||||
expected.initial = true;
|
||||
expect(battle.log.events).toEqual([expected]);
|
||||
expect(battle.getBootstrapEvents()).toEqual([expected]);
|
||||
});
|
||||
|
||||
it("checks if a player is able to play", function () {
|
||||
|
|
|
@ -271,20 +271,22 @@ module TS.SpaceTac {
|
|||
this.throwInitiative();
|
||||
iforeach(this.iships(), ship => ship.startBattle());
|
||||
this.advanceToNextShip();
|
||||
|
||||
// For now, we inject bootstrap events in the log
|
||||
this.getBootstrapEvents().forEach(event => this.log.add(event));
|
||||
}
|
||||
|
||||
// Force an injection of events in the battle log to simulate the initial state
|
||||
// For instance, this may be called after 'start', to use the log subscription system
|
||||
// to initialize a battle UI
|
||||
// Attributes 'play_order' and 'playing_ship' should be defined before calling this
|
||||
injectInitialEvents(): void {
|
||||
var log = this.log;
|
||||
/**
|
||||
* Get a set of minimal events required to reach current state from an empty state.
|
||||
*/
|
||||
getBootstrapEvents(): BaseBattleEvent[] {
|
||||
let result: BaseBattleEvent[] = [];
|
||||
|
||||
// Simulate initial ship placement
|
||||
this.play_order.forEach(ship => {
|
||||
let event = new MoveEvent(ship, ship.arena_x, ship.arena_y, 0);
|
||||
event.initial = true;
|
||||
log.add(event);
|
||||
result.push(event);
|
||||
});
|
||||
|
||||
// Indicate emergency stasis
|
||||
|
@ -292,7 +294,7 @@ module TS.SpaceTac {
|
|||
if (!ship.alive) {
|
||||
let event = new DeathEvent(ship);
|
||||
event.initial = true;
|
||||
log.add(event);
|
||||
result.push(event);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -300,15 +302,17 @@ module TS.SpaceTac {
|
|||
this.drones.forEach(drone => {
|
||||
let event = new DroneDeployedEvent(drone);
|
||||
event.initial = true;
|
||||
log.add(event);
|
||||
result.push(event);
|
||||
});
|
||||
|
||||
// Simulate game turn
|
||||
if (this.playing_ship) {
|
||||
let event = new ShipChangeEvent(this.playing_ship, this.playing_ship);
|
||||
event.initial = true;
|
||||
log.add(event);
|
||||
result.push(event);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/// <reference path="events/BaseLogEvent.ts"/>
|
||||
/// <reference path="events/BaseBattleEvent.ts"/>
|
||||
|
||||
module TS.SpaceTac {
|
||||
// Check a single game log event
|
||||
function checkEvent(got: BaseLogEvent, ship: Ship, code: string,
|
||||
function checkEvent(got: BaseBattleEvent, ship: Ship, code: string,
|
||||
target_ship: Ship | null = null, target_x: number | null = null, target_y: number | null = null): void {
|
||||
if (target_ship) {
|
||||
if (target_x === null) {
|
||||
|
@ -33,7 +33,7 @@ module TS.SpaceTac {
|
|||
}
|
||||
|
||||
// Fake event
|
||||
class FakeEvent extends BaseLogEvent {
|
||||
class FakeEvent extends BaseBattleEvent {
|
||||
constructor() {
|
||||
super("fake", new Ship());
|
||||
}
|
||||
|
@ -42,10 +42,10 @@ module TS.SpaceTac {
|
|||
describe("BattleLog", function () {
|
||||
it("forwards events to subscribers, until unsubscribe", function () {
|
||||
var log = new BattleLog();
|
||||
var received: BaseLogEvent[] = [];
|
||||
var received: BaseBattleEvent[] = [];
|
||||
var fake = new FakeEvent();
|
||||
|
||||
var sub = log.subscribe(function (event: BaseLogEvent) {
|
||||
var sub = log.subscribe(function (event: BaseBattleEvent) {
|
||||
received.push(event);
|
||||
});
|
||||
|
||||
|
@ -74,18 +74,14 @@ module TS.SpaceTac {
|
|||
it("can receive simulated initial state events", function () {
|
||||
let battle = Battle.newQuickRandom(true, 1, 4);
|
||||
let playing = nn(battle.playing_ship);
|
||||
battle.log.clear();
|
||||
battle.log.addFilter("value");
|
||||
expect(battle.log.events.length).toBe(0);
|
||||
|
||||
battle.injectInitialEvents();
|
||||
|
||||
expect(battle.log.events.length).toBe(9);
|
||||
let result = battle.getBootstrapEvents();
|
||||
expect(result.length).toBe(9);
|
||||
for (var i = 0; i < 8; i++) {
|
||||
checkEvent(battle.log.events[i], battle.play_order[i], "move", null,
|
||||
checkEvent(result[i], battle.play_order[i], "move", null,
|
||||
battle.play_order[i].arena_x, battle.play_order[i].arena_y);
|
||||
}
|
||||
checkEvent(battle.log.events[8], playing, "ship_change", playing);
|
||||
checkEvent(result[8], playing, "ship_change", playing);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -2,14 +2,14 @@ module TS.SpaceTac {
|
|||
/**
|
||||
* Function called to inform subscribers of new events.
|
||||
*/
|
||||
export type LogSubscriber = (event: BaseLogEvent) => any;
|
||||
export type LogSubscriber = (event: BaseBattleEvent) => any;
|
||||
|
||||
// Log of a battle
|
||||
// This keeps track of all events in a battle
|
||||
// It also allows to register a callback to receive these events
|
||||
export class BattleLog {
|
||||
// Full list of battle events
|
||||
events: BaseLogEvent[];
|
||||
events: BaseBattleEvent[];
|
||||
|
||||
// List of subscribers
|
||||
private subscribers: LogSubscriber[];
|
||||
|
@ -34,7 +34,7 @@ module TS.SpaceTac {
|
|||
}
|
||||
|
||||
// Add a battle event to the log
|
||||
add(event: BaseLogEvent): void {
|
||||
add(event: BaseBattleEvent): void {
|
||||
// Apply filters
|
||||
var filtered = false;
|
||||
this.filters.forEach((code: string) => {
|
||||
|
|
|
@ -22,16 +22,19 @@ module TS.SpaceTac.Specs {
|
|||
let battle = new Battle();
|
||||
let attacker = battle.fleets[0].addShip();
|
||||
let defender = battle.fleets[1].addShip();
|
||||
stats.watchLog(battle.log, battle.fleets[0]);
|
||||
stats.processLog(battle.log, battle.fleets[0]);
|
||||
expect(stats.stats).toEqual({});
|
||||
|
||||
battle.log.add(new DamageEvent(attacker, 10, 12));
|
||||
stats.processLog(battle.log, battle.fleets[0]);
|
||||
expect(stats.stats).toEqual({ "Damage dealt": [0, 22] });
|
||||
|
||||
battle.log.add(new DamageEvent(defender, 40, 0));
|
||||
stats.processLog(battle.log, battle.fleets[0]);
|
||||
expect(stats.stats).toEqual({ "Damage dealt": [40, 22] });
|
||||
|
||||
battle.log.add(new DamageEvent(attacker, 5, 4));
|
||||
stats.processLog(battle.log, battle.fleets[0]);
|
||||
expect(stats.stats).toEqual({ "Damage dealt": [40, 31] });
|
||||
})
|
||||
|
||||
|
@ -40,13 +43,15 @@ module TS.SpaceTac.Specs {
|
|||
let battle = new Battle();
|
||||
let attacker = battle.fleets[0].addShip();
|
||||
let defender = battle.fleets[1].addShip();
|
||||
stats.watchLog(battle.log, battle.fleets[0]);
|
||||
stats.processLog(battle.log, battle.fleets[0]);
|
||||
expect(stats.stats).toEqual({});
|
||||
|
||||
battle.log.add(new MoveEvent(attacker, 0, 0, 10));
|
||||
stats.processLog(battle.log, battle.fleets[0]);
|
||||
expect(stats.stats).toEqual({ "Move distance (km)": [10, 0] });
|
||||
|
||||
battle.log.add(new MoveEvent(defender, 0, 0, 58));
|
||||
stats.processLog(battle.log, battle.fleets[0]);
|
||||
expect(stats.stats).toEqual({ "Move distance (km)": [10, 58] });
|
||||
})
|
||||
|
||||
|
@ -55,13 +60,15 @@ module TS.SpaceTac.Specs {
|
|||
let battle = new Battle();
|
||||
let attacker = battle.fleets[0].addShip();
|
||||
let defender = battle.fleets[1].addShip();
|
||||
stats.watchLog(battle.log, battle.fleets[0]);
|
||||
stats.processLog(battle.log, battle.fleets[0]);
|
||||
expect(stats.stats).toEqual({});
|
||||
|
||||
battle.log.add(new DroneDeployedEvent(new Drone(attacker)));
|
||||
stats.processLog(battle.log, battle.fleets[0]);
|
||||
expect(stats.stats).toEqual({ "Drones deployed": [1, 0] });
|
||||
|
||||
battle.log.add(new DroneDeployedEvent(new Drone(defender)));
|
||||
stats.processLog(battle.log, battle.fleets[0]);
|
||||
expect(stats.stats).toEqual({ "Drones deployed": [1, 1] });
|
||||
})
|
||||
})
|
||||
|
|
|
@ -35,10 +35,12 @@ module TS.SpaceTac {
|
|||
}
|
||||
|
||||
/**
|
||||
* Watch a battle log to automatically feed the collector
|
||||
* Process a battle log
|
||||
*/
|
||||
watchLog(log: BattleLog, attacker: Fleet) {
|
||||
log.subscribe(event => {
|
||||
processLog(log: BattleLog, attacker: Fleet) {
|
||||
this.stats = {};
|
||||
|
||||
log.events.forEach(event => {
|
||||
if (event instanceof DamageEvent) {
|
||||
this.addStat("Damage dealt", event.hull + event.shield, event.ship.fleet !== attacker);
|
||||
} else if (event instanceof MoveEvent) {
|
||||
|
|
|
@ -196,7 +196,7 @@ module TS.SpaceTac {
|
|||
}
|
||||
|
||||
// Add an event to the battle log, if any
|
||||
addBattleEvent(event: BaseLogEvent): void {
|
||||
addBattleEvent(event: BaseBattleEvent): void {
|
||||
var battle = this.getBattle();
|
||||
if (battle && battle.log) {
|
||||
battle.log.add(event);
|
||||
|
|
|
@ -85,7 +85,7 @@ module TS.SpaceTac {
|
|||
var encounter = this.tryGenerateEncounter();
|
||||
if (encounter) {
|
||||
var battle = new Battle(fleet, encounter);
|
||||
battle.log.subscribe((event: BaseLogEvent) => {
|
||||
battle.log.subscribe((event: BaseBattleEvent) => {
|
||||
if (event.code === "endbattle") {
|
||||
var endbattle = <EndBattleEvent>event;
|
||||
if (!endbattle.outcome.draw && endbattle.outcome.winner !== encounter) {
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
module TS.SpaceTac {
|
||||
// Base class for a BattleLog event
|
||||
export class BaseLogEvent {
|
||||
/**
|
||||
* Base class for battle events
|
||||
*
|
||||
* Events are the proper way to modify the battle state
|
||||
*
|
||||
* All events may be applied either forward or backward on a battle state
|
||||
*/
|
||||
export class BaseBattleEvent {
|
||||
// Code of the event (its type)
|
||||
code: string;
|
||||
|
||||
|
@ -18,10 +24,22 @@ module TS.SpaceTac {
|
|||
this.ship = ship;
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the event forward on a battle state
|
||||
*/
|
||||
apply(battle: Battle) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the event backward (revert it) on a battle state
|
||||
*/
|
||||
revert(battle: Battle) {
|
||||
}
|
||||
}
|
||||
|
||||
// Base class for a BattleLog event linked to a ship
|
||||
export class BaseLogShipEvent extends BaseLogEvent {
|
||||
export class BaseLogShipEvent extends BaseBattleEvent {
|
||||
ship: Ship;
|
||||
|
||||
constructor(code: string, ship: Ship, target: Target | null = null) {
|
|
@ -1,4 +1,4 @@
|
|||
/// <reference path="BaseLogEvent.ts"/>
|
||||
/// <reference path="BaseBattleEvent.ts"/>
|
||||
|
||||
module TS.SpaceTac {
|
||||
// Event logged when a ship takes damage
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/// <reference path="BaseLogEvent.ts"/>
|
||||
/// <reference path="BaseBattleEvent.ts"/>
|
||||
|
||||
module TS.SpaceTac {
|
||||
// Event logged when a ship is dead
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/// <reference path="BaseLogEvent.ts"/>
|
||||
/// <reference path="BaseBattleEvent.ts"/>
|
||||
|
||||
module TS.SpaceTac {
|
||||
/**
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/// <reference path="BaseLogEvent.ts"/>
|
||||
/// <reference path="BaseBattleEvent.ts"/>
|
||||
|
||||
module TS.SpaceTac {
|
||||
// Event logged when a drone is deployed by a ship
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/// <reference path="BaseLogEvent.ts"/>
|
||||
/// <reference path="BaseBattleEvent.ts"/>
|
||||
|
||||
module TS.SpaceTac {
|
||||
// Event logged when a drone is destroyed
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/// <reference path="BaseLogEvent.ts"/>
|
||||
/// <reference path="BaseBattleEvent.ts"/>
|
||||
|
||||
module TS.SpaceTac {
|
||||
// Event logged when a sticky effect is added to a ship
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/// <reference path="BaseLogEvent.ts"/>
|
||||
/// <reference path="BaseBattleEvent.ts"/>
|
||||
|
||||
module TS.SpaceTac {
|
||||
// Event logged when a sticky effect is added to a ship
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/// <reference path="BaseLogEvent.ts"/>
|
||||
/// <reference path="BaseBattleEvent.ts"/>
|
||||
|
||||
module TS.SpaceTac {
|
||||
// Event logged when a sticky effect is removed from a ship
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/// <reference path="BaseLogEvent.ts"/>
|
||||
/// <reference path="BaseBattleEvent.ts"/>
|
||||
|
||||
module TS.SpaceTac {
|
||||
// Event logged when the battle ended
|
||||
// This is always the last event of a battle log
|
||||
export class EndBattleEvent extends BaseLogEvent {
|
||||
export class EndBattleEvent extends BaseBattleEvent {
|
||||
// Outcome of the battle
|
||||
outcome: BattleOutcome;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/// <reference path="BaseLogEvent.ts"/>
|
||||
/// <reference path="BaseBattleEvent.ts"/>
|
||||
|
||||
module TS.SpaceTac {
|
||||
// Event logged when a weapon is used on a target
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/// <reference path="BaseLogEvent.ts"/>
|
||||
/// <reference path="BaseBattleEvent.ts"/>
|
||||
|
||||
module TS.SpaceTac {
|
||||
// Event logged when a ship moves
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/// <reference path="BaseLogEvent.ts"/>
|
||||
/// <reference path="BaseBattleEvent.ts"/>
|
||||
|
||||
module TS.SpaceTac {
|
||||
// Battle event, when a ship turn ended, and advanced to a new one
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/// <reference path="BaseLogEvent.ts"/>
|
||||
/// <reference path="BaseBattleEvent.ts"/>
|
||||
|
||||
module TS.SpaceTac {
|
||||
// Event logged when a ship value or attribute changed
|
||||
|
|
|
@ -124,7 +124,7 @@ module TS.SpaceTac.UI {
|
|||
/**
|
||||
* Process a battle log event
|
||||
*/
|
||||
private processLogEvent(event: BaseLogEvent): number {
|
||||
private processLogEvent(event: BaseBattleEvent): number {
|
||||
if (event instanceof ShipChangeEvent) {
|
||||
if (event.new_ship === this.ship) {
|
||||
this.play_order.text = "";
|
||||
|
|
|
@ -257,6 +257,8 @@ module TS.SpaceTac.UI {
|
|||
|
||||
this.gameui.session.setBattleEnded();
|
||||
|
||||
this.battle.stats.processLog(this.battle.log, this.player.fleet);
|
||||
|
||||
let dialog = new OutcomeDialog(this, this.player, this.battle.outcome, this.battle.stats);
|
||||
dialog.moveToLayer(this.outcome_layer);
|
||||
} else {
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
module TS.SpaceTac.UI {
|
||||
// Processor of battle log events
|
||||
// This will process incoming battle events, and update the battleview accordingly
|
||||
/**
|
||||
* Processor of events coming from the battle log
|
||||
*
|
||||
* This will bind to the battle log to receive new events, and update
|
||||
* the battle view accordingly.
|
||||
*
|
||||
* It is also possible to go back/forward in time.
|
||||
*/
|
||||
export class LogProcessor {
|
||||
// Link to the battle view
|
||||
private view: BattleView;
|
||||
|
@ -18,7 +24,7 @@ module TS.SpaceTac.UI {
|
|||
private delayed = false;
|
||||
|
||||
// Processing queue, when delay is active
|
||||
private queue: BaseLogEvent[] = [];
|
||||
private queue: BaseBattleEvent[] = [];
|
||||
|
||||
// Forward events to other subscribers
|
||||
private forwarding: LogSubscriber[] = [];
|
||||
|
@ -27,6 +33,19 @@ module TS.SpaceTac.UI {
|
|||
this.view = view;
|
||||
this.battle = view.battle;
|
||||
this.log = view.battle.log;
|
||||
|
||||
/*view.inputs.bindCheat("PageUp", "Step backward", () => {
|
||||
this.stepBackward();
|
||||
});
|
||||
view.inputs.bindCheat("PageDown", "Step forward", () => {
|
||||
this.stepForward();
|
||||
});
|
||||
view.inputs.bindCheat("Home", "Jump to beginning", () => {
|
||||
this.jumpToStart();
|
||||
});
|
||||
view.inputs.bindCheat("End", "Jump to end", () => {
|
||||
this.jumpToEnd();
|
||||
});*/
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -34,8 +53,7 @@ module TS.SpaceTac.UI {
|
|||
*/
|
||||
start() {
|
||||
this.subscription = this.log.subscribe(event => this.processBattleEvent(event));
|
||||
this.battle.injectInitialEvents();
|
||||
this.battle.stats.watchLog(this.battle.log, this.view.player.fleet);
|
||||
this.battle.getBootstrapEvents().forEach(event => this.processBattleEvent(event));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -46,7 +64,7 @@ module TS.SpaceTac.UI {
|
|||
*
|
||||
* The callback may return the duration it needs to display the change.
|
||||
*/
|
||||
register(callback: (event: BaseLogEvent) => number) {
|
||||
register(callback: (event: BaseBattleEvent) => number) {
|
||||
this.forwarding.push(event => {
|
||||
let duration = callback(event);
|
||||
if (duration) {
|
||||
|
@ -92,7 +110,7 @@ module TS.SpaceTac.UI {
|
|||
/**
|
||||
* Process a single event
|
||||
*/
|
||||
processBattleEvent(event: BaseLogEvent) {
|
||||
processBattleEvent(event: BaseBattleEvent) {
|
||||
if (!this.subscription) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ module TS.SpaceTac.UI {
|
|||
* Manager for keyboard/mouse/touch events.
|
||||
*/
|
||||
export class InputManager {
|
||||
private debug = false
|
||||
private view: BaseView
|
||||
private game: MainUI
|
||||
private input: Phaser.Input
|
||||
|
@ -48,7 +49,10 @@ module TS.SpaceTac.UI {
|
|||
});
|
||||
|
||||
this.input.keyboard.addCallbacks(this, undefined, (event: KeyboardEvent) => {
|
||||
// console.debug(event);
|
||||
if (this.debug) {
|
||||
console.log(event);
|
||||
}
|
||||
|
||||
if (!contains(["Control", "Shift", "Alt", "Meta"], event.key)) {
|
||||
this.keyPress(event.key);
|
||||
if (event.code != event.key) {
|
||||
|
|
Loading…
Reference in a new issue