Refactored MoveEvent for new battle log flow
This commit is contained in:
parent
83807beb20
commit
8c0aa73ab7
35
src/core/ArenaLocation.ts
Normal file
35
src/core/ArenaLocation.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
module TS.SpaceTac {
|
||||
/**
|
||||
* Location in the arena
|
||||
*/
|
||||
export class ArenaLocation {
|
||||
x: number
|
||||
y: number
|
||||
|
||||
constructor(x = 0, y = 0) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the distance to another location
|
||||
*/
|
||||
getDistanceTo(other: ArenaLocation) {
|
||||
let dx = this.x - other.x;
|
||||
let dy = this.y - other.y;
|
||||
return Math.sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Location in the arena, with a facing angle in radians
|
||||
*/
|
||||
export class ArenaLocationAngle extends ArenaLocation {
|
||||
angle: number
|
||||
|
||||
constructor(x = 0, y = 0, angle = 0) {
|
||||
super(x, y);
|
||||
this.angle = angle;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -284,7 +284,7 @@ module TS.SpaceTac {
|
|||
|
||||
// Simulate initial ship placement
|
||||
this.play_order.forEach(ship => {
|
||||
let event = new MoveEvent(ship, ship.arena_x, ship.arena_y, 0);
|
||||
let event = new MoveEvent(ship, ship.location, ship.location);
|
||||
event.initial = true;
|
||||
result.push(event);
|
||||
});
|
||||
|
|
|
@ -46,11 +46,11 @@ module TS.SpaceTac.Specs {
|
|||
stats.processLog(battle.log, battle.fleets[0]);
|
||||
expect(stats.stats).toEqual({});
|
||||
|
||||
battle.log.add(new MoveEvent(attacker, 0, 0, 10));
|
||||
battle.log.add(new MoveEvent(attacker, new ArenaLocationAngle(0, 0), new ArenaLocationAngle(10, 0)));
|
||||
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));
|
||||
battle.log.add(new MoveEvent(defender, new ArenaLocationAngle(10, 5), new ArenaLocationAngle(10, 63)));
|
||||
stats.processLog(battle.log, battle.fleets[0]);
|
||||
expect(stats.stats).toEqual({ "Move distance (km)": [10, 58] });
|
||||
})
|
||||
|
|
|
@ -44,7 +44,7 @@ module TS.SpaceTac {
|
|||
if (event instanceof DamageEvent) {
|
||||
this.addStat("Damage dealt", event.hull + event.shield, event.ship.fleet !== attacker);
|
||||
} else if (event instanceof MoveEvent) {
|
||||
this.addStat("Move distance (km)", event.distance, event.ship.fleet === attacker);
|
||||
this.addStat("Move distance (km)", event.getDistance(), event.ship.fleet === attacker);
|
||||
} else if (event instanceof DroneDeployedEvent) {
|
||||
this.addStat("Drones deployed", 1, event.ship.fleet === attacker);
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ module TS.SpaceTac.Specs {
|
|||
expect(battle.log.events).toEqual([]);
|
||||
|
||||
ship.moveTo(70, 50);
|
||||
expect(battle.log.events).toEqual([new MoveEvent(ship, 70, 50, 20)]);
|
||||
expect(battle.log.events).toEqual([new MoveEvent(ship, new ArenaLocationAngle(50, 50, Math.PI), new ArenaLocationAngle(70, 50, 0))]);
|
||||
});
|
||||
|
||||
it("applies equipment cooldown", function () {
|
||||
|
|
|
@ -120,6 +120,13 @@ module TS.SpaceTac {
|
|||
model.slots.forEach(slot => this.addSlot(slot));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current location and angle of this ship
|
||||
*/
|
||||
get location(): ArenaLocationAngle {
|
||||
return new ArenaLocationAngle(this.arena_x, this.arena_y, this.arena_angle);
|
||||
}
|
||||
|
||||
// Returns true if the ship is able to play
|
||||
// If *check_ap* is true, ap_current=0 will make this function return false
|
||||
isAbleToPlay(check_ap: boolean = true): boolean {
|
||||
|
@ -426,7 +433,7 @@ module TS.SpaceTac {
|
|||
this.setArenaFacingAngle(angle);
|
||||
|
||||
if (log) {
|
||||
this.addBattleEvent(new MoveEvent(this, this.arena_x, this.arena_y, 0));
|
||||
this.addBattleEvent(new MoveEvent(this, copy(this.location), new ArenaLocationAngle(this.arena_x, this.arena_y, angle)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -437,13 +444,14 @@ module TS.SpaceTac {
|
|||
let dx = x - this.arena_x;
|
||||
let dy = y - this.arena_y;
|
||||
if (dx != 0 || dy != 0) {
|
||||
let start = copy(this.location);
|
||||
|
||||
let angle = Math.atan2(dy, dx);
|
||||
this.setArenaFacingAngle(angle);
|
||||
|
||||
this.setArenaPosition(x, y);
|
||||
|
||||
if (log) {
|
||||
this.addBattleEvent(new MoveEvent(this, x, y, Math.sqrt(dx * dx + dy * dy)));
|
||||
this.addBattleEvent(new MoveEvent(this, start, copy(this.location)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,10 +70,9 @@ module TS.SpaceTac {
|
|||
|
||||
expect(battle.log.events[1].code).toEqual("move");
|
||||
expect(battle.log.events[1].ship).toBe(ship);
|
||||
let target: any = battle.log.events[1].target;
|
||||
expect(target.ship).toBeNull();
|
||||
expect(target.x).toBeCloseTo(3.535533, 0.00001);
|
||||
expect(target.y).toBeCloseTo(3.535533, 0.00001);
|
||||
let dest = (<MoveEvent>battle.log.events[1]).end;
|
||||
expect(dest.x).toBeCloseTo(3.535533, 0.00001);
|
||||
expect(dest.y).toBeCloseTo(3.535533, 0.00001);
|
||||
});
|
||||
|
||||
it("can't move too much near another ship", function () {
|
||||
|
|
|
@ -3,8 +3,6 @@ module TS.SpaceTac {
|
|||
* 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)
|
||||
|
@ -26,15 +24,16 @@ module TS.SpaceTac {
|
|||
}
|
||||
|
||||
/**
|
||||
* Apply the event forward on a battle state
|
||||
* Apply the event on a battle state
|
||||
*/
|
||||
apply(battle: Battle) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the event backward (revert it) on a battle state
|
||||
* Get the reverse event
|
||||
*/
|
||||
revert(battle: Battle) {
|
||||
getReverse(): BaseBattleEvent {
|
||||
throw new Error("No reverse implemented");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
9
src/core/events/MoveEvent.spec.ts
Normal file
9
src/core/events/MoveEvent.spec.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
module TS.SpaceTac.Specs {
|
||||
describe("MoveEvent", function () {
|
||||
it("get reverse event", function () {
|
||||
let ship = new Ship();
|
||||
let event = new MoveEvent(ship, new ArenaLocationAngle(0, 0, 0), new ArenaLocationAngle(5, 10, 1.2));
|
||||
expect(event.getReverse()).toEqual(new MoveEvent(ship, new ArenaLocationAngle(5, 10, 1.2), new ArenaLocationAngle(0, 0, 0)));
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,19 +1,32 @@
|
|||
/// <reference path="BaseBattleEvent.ts"/>
|
||||
|
||||
module TS.SpaceTac {
|
||||
// Event logged when a ship moves
|
||||
export class MoveEvent extends BaseLogShipTargetEvent {
|
||||
// Distance traveled
|
||||
distance: number
|
||||
/**
|
||||
* Event making a ship move
|
||||
*/
|
||||
export class MoveEvent extends BaseLogShipEvent {
|
||||
// Previous location
|
||||
start: ArenaLocationAngle
|
||||
|
||||
// New facing angle, in radians
|
||||
facing_angle: number
|
||||
// New location
|
||||
end: ArenaLocationAngle
|
||||
|
||||
constructor(ship: Ship, x: number, y: number, distance: number) {
|
||||
super("move", ship, Target.newFromLocation(x, y));
|
||||
constructor(ship: Ship, start: ArenaLocationAngle, end: ArenaLocationAngle) {
|
||||
super("move", ship, Target.newFromLocation(end.x, end.y));
|
||||
|
||||
this.distance = distance;
|
||||
this.facing_angle = ship.arena_angle;
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
getReverse(): BaseBattleEvent {
|
||||
return new MoveEvent(this.ship, this.end, this.start);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the distance travelled
|
||||
*/
|
||||
getDistance(): number {
|
||||
return this.start.getDistanceTo(this.end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -166,7 +166,8 @@ module TS.SpaceTac.UI {
|
|||
this.displayEffect(`${event.hull + event.shield} damage`, false);
|
||||
return 0;
|
||||
} else if (event instanceof MoveEvent && !event.initial) {
|
||||
let duration = this.moveTo(event.target.x, event.target.y, event.facing_angle, true);
|
||||
this.moveTo(event.start.x, event.start.y, event.start.angle, false);
|
||||
let duration = this.moveTo(event.end.x, event.end.y, event.end.angle, true);
|
||||
return duration;
|
||||
} else {
|
||||
return 0;
|
||||
|
|
|
@ -66,8 +66,6 @@ module TS.SpaceTac.UI {
|
|||
|
||||
this.battle.timer = this.timer;
|
||||
|
||||
this.log_processor = new LogProcessor(this);
|
||||
|
||||
this.toggle_tactical_mode = new Toggle(
|
||||
() => this.arena.setTacticalMode(true),
|
||||
() => this.arena.setTacticalMode(false)
|
||||
|
@ -79,6 +77,7 @@ module TS.SpaceTac.UI {
|
|||
super.create();
|
||||
|
||||
var game = this.game;
|
||||
this.log_processor = new LogProcessor(this);
|
||||
|
||||
// Add layers
|
||||
this.layer_background = this.addLayer();
|
||||
|
|
58
src/ui/battle/LogProcessor.spec.ts
Normal file
58
src/ui/battle/LogProcessor.spec.ts
Normal file
|
@ -0,0 +1,58 @@
|
|||
/// <reference path="../TestGame.ts"/>
|
||||
/// <reference path="../../core/events/BaseBattleEvent.ts"/>
|
||||
|
||||
module TS.SpaceTac.UI.Specs {
|
||||
class FakeEvent extends BaseBattleEvent {
|
||||
diff: number
|
||||
|
||||
constructor(diff = 1) {
|
||||
super("fake");
|
||||
|
||||
this.diff = diff;
|
||||
}
|
||||
|
||||
apply(battle: Battle) {
|
||||
battle.turn += this.diff;
|
||||
}
|
||||
|
||||
getReverse(): BaseBattleEvent {
|
||||
return new FakeEvent(-this.diff);
|
||||
}
|
||||
}
|
||||
|
||||
describe("LogProcessor", function () {
|
||||
let testgame = setupBattleview();
|
||||
|
||||
it("steps forward and backward in time", function () {
|
||||
let battle = testgame.battleview.battle;
|
||||
battle.log.clear();
|
||||
let processor = new LogProcessor(testgame.battleview);
|
||||
processor.register(event => {
|
||||
event.apply(battle);
|
||||
return 0;
|
||||
});
|
||||
expect(battle.turn).toBe(1);
|
||||
|
||||
processor.stepForward();
|
||||
expect(battle.turn).toBe(1);
|
||||
|
||||
battle.log.add(new FakeEvent());
|
||||
expect(battle.turn).toBe(1);
|
||||
|
||||
processor.stepForward();
|
||||
expect(battle.turn).toBe(2);
|
||||
|
||||
processor.stepForward();
|
||||
expect(battle.turn).toBe(2);
|
||||
|
||||
processor.stepBackward();
|
||||
expect(battle.turn).toBe(1);
|
||||
|
||||
processor.stepBackward();
|
||||
expect(battle.turn).toBe(1);
|
||||
|
||||
processor.stepForward();
|
||||
expect(battle.turn).toBe(2);
|
||||
})
|
||||
})
|
||||
}
|
|
@ -9,32 +9,35 @@ module TS.SpaceTac.UI {
|
|||
*/
|
||||
export class LogProcessor {
|
||||
// Link to the battle view
|
||||
private view: BattleView;
|
||||
private view: BattleView
|
||||
|
||||
// Link to the battle
|
||||
private battle: Battle;
|
||||
private battle: Battle
|
||||
|
||||
// Link to the battle log
|
||||
private log: BattleLog;
|
||||
private log: BattleLog
|
||||
|
||||
// Subscription identifier
|
||||
private subscription: any = null;
|
||||
private subscription: any = null
|
||||
|
||||
// Delay before processing next events
|
||||
private delayed = false;
|
||||
private delayed = false
|
||||
|
||||
// Processing queue, when delay is active
|
||||
private queue: BaseBattleEvent[] = [];
|
||||
private queue: BaseBattleEvent[] = []
|
||||
|
||||
// Forward events to other subscribers
|
||||
private forwarding: LogSubscriber[] = [];
|
||||
private forwarding: LogSubscriber[] = []
|
||||
|
||||
// Current position in the battle log
|
||||
private cursor = -1;
|
||||
|
||||
constructor(view: BattleView) {
|
||||
this.view = view;
|
||||
this.battle = view.battle;
|
||||
this.log = view.battle.log;
|
||||
|
||||
/*view.inputs.bindCheat("PageUp", "Step backward", () => {
|
||||
view.inputs.bindCheat("PageUp", "Step backward", () => {
|
||||
this.stepBackward();
|
||||
});
|
||||
view.inputs.bindCheat("PageDown", "Step forward", () => {
|
||||
|
@ -45,7 +48,7 @@ module TS.SpaceTac.UI {
|
|||
});
|
||||
view.inputs.bindCheat("End", "Jump to end", () => {
|
||||
this.jumpToEnd();
|
||||
});*/
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -56,6 +59,42 @@ module TS.SpaceTac.UI {
|
|||
this.battle.getBootstrapEvents().forEach(event => this.processBattleEvent(event));
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a step backward in time
|
||||
*/
|
||||
stepBackward() {
|
||||
if (this.cursor >= 0) {
|
||||
this.processBattleEvent(this.log.events[this.cursor].getReverse());
|
||||
this.cursor -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a step forward in time
|
||||
*/
|
||||
stepForward() {
|
||||
if (this.cursor < this.log.events.length - 1) {
|
||||
this.cursor += 1;
|
||||
this.processBattleEvent(this.log.events[this.cursor]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Jump to the start of the log
|
||||
*
|
||||
* This will rewind all applied event
|
||||
*/
|
||||
jumpToStart() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Jump to the end of the log
|
||||
*
|
||||
* This will apply all remaining event
|
||||
*/
|
||||
jumpToEnd() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a sub-subscriber.
|
||||
*
|
||||
|
@ -111,10 +150,6 @@ module TS.SpaceTac.UI {
|
|||
* Process a single event
|
||||
*/
|
||||
processBattleEvent(event: BaseBattleEvent) {
|
||||
if (!this.subscription) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.delayed) {
|
||||
this.queue.push(event);
|
||||
return;
|
||||
|
|
Loading…
Reference in a new issue