diff --git a/README.md b/README.md
index c8e78f1..87edf2f 100644
--- a/README.md
+++ b/README.md
@@ -27,12 +27,17 @@ After making changes to sources, you need to recompile:
In combat, a ship's vitals are represented by the HSP system (Hull-Shield-Power):
-* **Hull** - Amout of damage that a ship can receive before having to shut down all its systems
+* **Hull** - Amount of damage that a ship can sustain before having to engage emergency stasis
* **Shield** - Amount of damage that the shield equipments may absorb to protect the Hull
* **Power** - Available action points (some actions require more power than others)
These values will be changed by various effects (usage of equipments, sustained damage...).
+Once the Hull of a ship is fully damaged (Hull=0), the ship engages its ESP, or Emergency
+Statis Protocol. This protocol activates a statis field that protects the ship for the
+remaining of the battle, preventing any further damage, but rendering it fully inoperent.
+For battle purpose, the ship is to be considered "dead".
+
### Attributes
Attributes represent a ship's ability to use its HSP system:
@@ -67,11 +72,11 @@ Each equipment has minimal skill requirements to be used. For example, a weapon
and "energy >= 3" to be equipped. A ship that does not meet these requirements will not be able to use
the equipment.
-As for attributes, skill values are controlled by equipments, effects and level up.
+Like for attributes, skill values are controlled by equipments, effects and level up.
-If an equipped item has a requirement of "time >= 2", that the ship has time skill of exactly 2, and that a
-temporary effect of "time -1" is active, the requirement is no longer fulfilled and the equipped item
-is then temporarily disabled (no more effects and cannot be used), until the "time -1" effect is lifted.
+If an equipped item has a requirement of "time skill >= 2", that the ship has "time skill" of exactly 2, and
+that a temporary effect of "time skill -1" is active, the requirement is no longer fulfilled and the equipped
+item is then temporarily disabled (no more effects and cannot be used), until the "time skill -1" effect is lifted.
## Drones
diff --git a/TODO b/TODO
index 978706d..06f9b26 100644
--- a/TODO
+++ b/TODO
@@ -1,10 +1,11 @@
* Drones: add tooltip
* Drones: add hull points and take area damage
* Drones: change the sprite angle for deploy animation
-* Better display of effects over ship sprite (repairs, sticky effects...)
* Add a battle log display
* Organize arena objects and information in layers
+* Prevent arena effects information (eg. "shield -36") to overflow out of the arena
* Allow to cancel last moves
+* Identify ships in emergency stasis more clearly
* Add more visual effects to weapons, hits and explosions
* Effect should be random in a range (eg. "damage target 50-75")
* Add an overload/cooling system
diff --git a/out/assets/images/battle/attributes/powercapacity.png b/out/assets/images/battle/attributes/powercapacity.png
new file mode 100644
index 0000000..7247fe7
Binary files /dev/null and b/out/assets/images/battle/attributes/powercapacity.png differ
diff --git a/src/core/Ship.spec.ts b/src/core/Ship.spec.ts
index 1b88d80..c7155a3 100644
--- a/src/core/Ship.spec.ts
+++ b/src/core/Ship.spec.ts
@@ -107,8 +107,8 @@ module TS.SpaceTac.Specs {
expect(ship.values.hull.get()).toEqual(40);
expect(ship.values.shield.get()).toEqual(80);
expect(battle.log.events.length).toBe(3);
- expect(battle.log.events[0]).toEqual(new ValueChangeEvent(ship, ship.values.shield));
- expect(battle.log.events[1]).toEqual(new ValueChangeEvent(ship, ship.values.hull));
+ expect(battle.log.events[0]).toEqual(new ValueChangeEvent(ship, ship.values.shield, -20));
+ expect(battle.log.events[1]).toEqual(new ValueChangeEvent(ship, ship.values.hull, -10));
expect(battle.log.events[2]).toEqual(new DamageEvent(ship, 10, 20));
battle.log.clear();
diff --git a/src/core/Ship.ts b/src/core/Ship.ts
index 0ac82e3..3294647 100644
--- a/src/core/Ship.ts
+++ b/src/core/Ship.ts
@@ -195,20 +195,20 @@ module TS.SpaceTac {
* Returns true if the value changed.
*/
setValue(name: keyof ShipValues, value: number, offset = false, log = true): boolean {
- let changed: boolean;
+ let diff = 0;
let val = this.values[name];
if (offset) {
- changed = val.add(value);
+ diff = val.add(value);
} else {
- changed = val.set(value);
+ diff = val.set(value);
}
- if (changed && log) {
- this.addBattleEvent(new ValueChangeEvent(this, val));
+ if (log && diff != 0) {
+ this.addBattleEvent(new ValueChangeEvent(this, val, diff));
}
- return changed;
+ return diff != 0;
}
/**
@@ -226,10 +226,8 @@ module TS.SpaceTac {
* Returns true if the value changed.
*/
setAttribute(name: keyof ShipAttributes, value: number, log = true): boolean {
- let changed: boolean;
let attr = this.attributes[name];
-
- changed = attr.set(value);
+ let diff = attr.set(value);
// TODO more generic
if (name == "power_capacity") {
@@ -240,11 +238,11 @@ module TS.SpaceTac {
this.values.hull.setMaximal(attr.get());
}
- if (changed && log) {
- this.addBattleEvent(new ValueChangeEvent(this, attr));
+ if (log && diff != 0) {
+ this.addBattleEvent(new ValueChangeEvent(this, attr, diff));
}
- return changed;
+ return diff != 0;
}
// Initialize the action points counter
diff --git a/src/core/ShipValue.spec.ts b/src/core/ShipValue.spec.ts
index a8e7872..8e7aa7c 100644
--- a/src/core/ShipValue.spec.ts
+++ b/src/core/ShipValue.spec.ts
@@ -39,34 +39,34 @@ module TS.SpaceTac {
expect(attr.get()).toBe(50);
});
- it("tells if value changed", function () {
- var result: boolean;
+ it("tells the value variation", function () {
+ var result: number;
var attr = new ShipValue("test", 50, 100);
expect(attr.get()).toBe(50);
result = attr.set(51);
- expect(result).toBe(true);
+ expect(result).toBe(1);
result = attr.set(51);
- expect(result).toBe(false);
+ expect(result).toBe(0);
result = attr.add(1);
- expect(result).toBe(true);
+ expect(result).toBe(1);
result = attr.add(0);
- expect(result).toBe(false);
+ expect(result).toBe(0);
result = attr.add(1000);
- expect(result).toBe(true);
+ expect(result).toBe(48);
result = attr.add(2000);
- expect(result).toBe(false);
+ expect(result).toBe(0);
result = attr.set(-500);
- expect(result).toBe(true);
+ expect(result).toBe(-100);
result = attr.add(-600);
- expect(result).toBe(false);
+ expect(result).toBe(0);
});
});
}
diff --git a/src/core/ShipValue.ts b/src/core/ShipValue.ts
index bf46f33..612a433 100644
--- a/src/core/ShipValue.ts
+++ b/src/core/ShipValue.ts
@@ -36,13 +36,13 @@ module TS.SpaceTac {
/**
* Set an absolute value
*
- * Returns true if the value changed
+ * Returns the variation in value
*/
- set(value: number): boolean {
+ set(value: number): number {
var old_value = this.current;
this.current = value;
this.fix();
- return this.current !== old_value;
+ return this.current - old_value;
}
/**
@@ -50,11 +50,11 @@ module TS.SpaceTac {
*
* Returns true if the value changed
*/
- add(value: number): boolean {
+ add(value: number): number {
var old_value = this.current;
this.current += value;
this.fix();
- return this.current !== old_value;
+ return this.current - old_value;
}
/**
diff --git a/src/core/ai/BullyAI.spec.ts b/src/core/ai/BullyAI.spec.ts
index aa29179..1e52aff 100644
--- a/src/core/ai/BullyAI.spec.ts
+++ b/src/core/ai/BullyAI.spec.ts
@@ -235,17 +235,13 @@ module TS.SpaceTac.Specs {
expect(battle.log.events.length).toBe(7);
expect(battle.log.events[0]).toEqual(new MoveEvent(ship1, 2, 0));
- expect(battle.log.events[1]).toEqual(new ValueChangeEvent(ship1,
- new ShipValue("power", 2, 10)));
+ expect(battle.log.events[1]).toEqual(new ValueChangeEvent(ship1, new ShipValue("power", 2, 10), -4));
expect(battle.log.events[2]).toEqual(new FireEvent(ship1, weapon, Target.newFromShip(ship2)));
- expect(battle.log.events[3]).toEqual(new ValueChangeEvent(ship2,
- new ShipValue("shield", 0)));
- expect(battle.log.events[4]).toEqual(new ValueChangeEvent(ship2,
- new ShipValue("hull", 5)));
+ expect(battle.log.events[3]).toEqual(new ValueChangeEvent(ship2, new ShipValue("shield", 0), -10));
+ expect(battle.log.events[4]).toEqual(new ValueChangeEvent(ship2, new ShipValue("hull", 5), -10));
expect(battle.log.events[5]).toEqual(new DamageEvent(ship2, 10, 10));
- expect(battle.log.events[6]).toEqual(new ValueChangeEvent(ship1,
- new ShipValue("power", 1, 10)));
+ expect(battle.log.events[6]).toEqual(new ValueChangeEvent(ship1, new ShipValue("power", 1, 10), -1));
});
});
}
diff --git a/src/core/events/ValueChangeEvent.ts b/src/core/events/ValueChangeEvent.ts
index d70fab4..b186d15 100644
--- a/src/core/events/ValueChangeEvent.ts
+++ b/src/core/events/ValueChangeEvent.ts
@@ -3,13 +3,17 @@
module TS.SpaceTac {
// Event logged when a ship value or attribute changed
export class ValueChangeEvent extends BaseLogEvent {
- // Saved version of the value
+ // Saved version of the current value
value: ShipValue;
- constructor(ship: Ship, value: ShipValue) {
+ // Value variation
+ diff: number;
+
+ constructor(ship: Ship, value: ShipValue, diff: number) {
super("value", ship);
this.value = copy(value);
+ this.diff = diff;
}
}
}
diff --git a/src/ui/Preload.ts b/src/ui/Preload.ts
index 8ccb25b..84b66f5 100644
--- a/src/ui/Preload.ts
+++ b/src/ui/Preload.ts
@@ -56,6 +56,7 @@ module TS.SpaceTac.UI {
this.loadImage("battle/actions/deploy-repairdrone.png");
this.loadImage("battle/weapon/bullet.png");
this.loadImage("battle/attributes/power.png");
+ this.loadImage("battle/attributes/powercapacity.png");
this.loadImage("battle/attributes/effect-increase.png");
this.loadImage("battle/attributes/effect-decrease.png");
this.loadImage("battle/attributes/effect-limit.png");
diff --git a/src/ui/battle/Arena.ts b/src/ui/battle/Arena.ts
index 143f3ff..5b3f92c 100644
--- a/src/ui/battle/Arena.ts
+++ b/src/ui/battle/Arena.ts
@@ -2,6 +2,9 @@ module TS.SpaceTac.UI {
// Graphical representation of a battle
// This is the area in the BattleView that will display ships with their real positions
export class Arena extends Phaser.Group {
+ // Link to battleview
+ battleview: BattleView;
+
// Arena background
background: Phaser.Button;
@@ -11,9 +14,6 @@ module TS.SpaceTac.UI {
// Input callback to receive mouse move events
private input_callback: any;
- // Link to battleview
- private battleview: BattleView;
-
// List of ship sprites
private ship_sprites: ArenaShip[] = [];
@@ -75,8 +75,8 @@ module TS.SpaceTac.UI {
// Initialize state (create sprites)
init(): void {
// Add ship sprites
- this.battleview.battle.play_order.forEach((ship: Ship) => {
- var sprite = new ArenaShip(this.battleview, ship);
+ this.battleview.battle.play_order.forEach(ship => {
+ var sprite = new ArenaShip(this, ship);
this.addChild(sprite);
this.ship_sprites.push(sprite);
});
@@ -92,6 +92,7 @@ module TS.SpaceTac.UI {
var sprite = this.findShipSprite(ship);
if (sprite) {
sprite.alpha = 0.5;
+ sprite.displayEffect("Emergency Stasis", false);
}
}
diff --git a/src/ui/battle/ArenaShip.spec.ts b/src/ui/battle/ArenaShip.spec.ts
new file mode 100644
index 0000000..f964a4a
--- /dev/null
+++ b/src/ui/battle/ArenaShip.spec.ts
@@ -0,0 +1,24 @@
+///
+
+module TS.SpaceTac.UI.Specs {
+ describe("ArenaShip", () => {
+ inbattleview_it("adds effects display", (battleview: BattleView) => {
+ let ship = battleview.battle.playing_ship;
+ let sprite = battleview.arena.findShipSprite(ship);
+
+ expect(sprite.effects.children.length).toBe(0);
+
+ sprite.displayValueChanged(new ValueChangeEvent(ship, ship.attributes.power_recovery, -4));
+
+ expect(sprite.effects.children.length).toBe(1);
+ let t1 = sprite.effects.getChildAt(0);
+ expect(t1.text).toBe("power recovery -4");
+
+ sprite.displayValueChanged(new ValueChangeEvent(ship, ship.values.shield, 12));
+
+ expect(sprite.effects.children.length).toBe(2);
+ let t2 = sprite.effects.getChildAt(1);
+ expect(t2.text).toBe("shield +12");
+ });
+ });
+}
diff --git a/src/ui/battle/ArenaShip.ts b/src/ui/battle/ArenaShip.ts
index e9c628e..fe5f084 100644
--- a/src/ui/battle/ArenaShip.ts
+++ b/src/ui/battle/ArenaShip.ts
@@ -16,30 +16,38 @@ module TS.SpaceTac.UI {
// Frame to indicate the owner of the ship, and if it is playing
frame: Phaser.Image;
+ // Effects display
+ effects: Phaser.Group;
+
// Create a ship sprite usable in the Arena
- constructor(battleview: BattleView, ship: Ship) {
- super(battleview.game);
+ constructor(parent: Arena, ship: Ship) {
+ super(parent.game);
+ let battleview = parent.battleview;
this.ship = ship;
this.enemy = this.ship.getPlayer() != battleview.player;
// Add ship sprite
- this.sprite = new Phaser.Button(battleview.game, 0, 0, "ship-" + ship.model + "-sprite");
+ this.sprite = new Phaser.Button(this.game, 0, 0, "ship-" + ship.model + "-sprite");
this.sprite.rotation = ship.arena_angle;
this.sprite.anchor.set(0.5, 0.5);
this.addChild(this.sprite);
// Add playing effect
- this.frame = new Phaser.Image(battleview.game, 0, 0, `battle-arena-ship-normal-${this.enemy ? "enemy" : "own"}`, 0);
+ this.frame = new Phaser.Image(this.game, 0, 0, `battle-arena-ship-normal-${this.enemy ? "enemy" : "own"}`, 0);
this.frame.anchor.set(0.5, 0.5);
this.addChild(this.frame);
// Add hover effect
- this.hover = new Phaser.Image(battleview.game, 0, 0, "battle-arena-ship-hover", 0);
+ this.hover = new Phaser.Image(this.game, 0, 0, "battle-arena-ship-hover", 0);
this.hover.anchor.set(0.5, 0.5);
this.hover.visible = false;
this.addChild(this.hover);
+ // Effects display
+ this.effects = new Phaser.Group(this.game);
+ this.addChild(this.effects);
+
// Handle input on ship sprite
Tools.setHoverClick(this.sprite, () => battleview.cursorOnShip(ship), () => battleview.cursorOffShip(ship), () => battleview.cursorClicked());
@@ -75,33 +83,28 @@ module TS.SpaceTac.UI {
}
}
- // Briefly display the damage done to the ship
- displayDamage(hull: number, shield: number) {
- if (hull > 0) {
- var hull_text = new Phaser.Text(this.game, -20, -20, Math.round(hull).toString(),
- { font: "bold 16pt Arial", align: "center", fill: "#eb4e4a" });
- hull_text.anchor.set(0.5, 0.5);
- this.addChild(hull_text);
- this.animateDamageText(hull_text);
- }
- if (shield > 0) {
- var shield_text = new Phaser.Text(this.game, 20, -20, Math.round(shield).toString(),
- { font: "bold 16pt Arial", align: "center", fill: "#2ad8dc" });
- shield_text.anchor.set(0.5, 0.5);
- this.addChild(shield_text);
- this.animateDamageText(shield_text);
- }
+ /**
+ * Briefly show an effect on this ship
+ */
+ displayEffect(message: string, beneficial: boolean) {
+ let text = new Phaser.Text(this.game, 0, 20 * this.effects.children.length, message, { font: "14pt Arial", fill: beneficial ? "#afe9c6" : "#e9afaf" });
+ this.effects.addChild(text);
+
+ this.effects.position.set(-this.effects.width / 2, this.sprite.height * 0.7);
+
+ this.game.tweens.removeFrom(this.effects);
+ this.effects.alpha = 1;
+ let tween = this.game.tweens.create(this.effects).to({ alpha: 0 }, 500).delay(1000).start();
+ tween.onComplete.addOnce(() => this.effects.removeAll(true));
}
- private animateDamageText(text: Phaser.Text) {
- text.alpha = 0;
- var tween = this.game.tweens.create(text);
- tween.to({ alpha: 1 }, 100, Phaser.Easing.Circular.In, false, 400);
- tween.to({ y: -50, alpha: 0 }, 1000, Phaser.Easing.Circular.In, false, 1000);
- tween.onComplete.addOnce(() => {
- text.destroy();
- });
- tween.start();
+ /**
+ * Display interesting changes in ship values
+ */
+ displayValueChanged(event: ValueChangeEvent) {
+ let diff = event.diff;
+ let name = event.value.name;
+ this.displayEffect(`${name} ${diff < 0 ? "-" : "+"}${Math.abs(diff)}`, diff >= 0);
}
}
}
diff --git a/src/ui/battle/LogProcessor.ts b/src/ui/battle/LogProcessor.ts
index 1d90259..0789fcd 100644
--- a/src/ui/battle/LogProcessor.ts
+++ b/src/ui/battle/LogProcessor.ts
@@ -72,10 +72,6 @@ module TS.SpaceTac.UI {
// Damage to ship
private processDamageEvent(event: DamageEvent): void {
- var sprite = this.view.arena.findShipSprite(event.ship);
- if (sprite) {
- sprite.displayDamage(event.hull, event.shield);
- }
var item = this.view.ship_list.findItem(event.ship);
if (item) {
item.setDamageHit();
@@ -92,10 +88,14 @@ module TS.SpaceTac.UI {
// Ship value changed
private processValueChangedEvent(event: ValueChangeEvent): void {
+ var sprite = this.view.arena.findShipSprite(event.ship);
+ sprite.displayValueChanged(event);
+
var item = this.view.ship_list.findItem(event.ship);
if (item) {
item.updateAttributes();
}
+
// TODO Update tooltip
}
diff --git a/src/ui/battle/ShipTooltip.ts b/src/ui/battle/ShipTooltip.ts
index 6413822..668c9c1 100644
--- a/src/ui/battle/ShipTooltip.ts
+++ b/src/ui/battle/ShipTooltip.ts
@@ -136,7 +136,7 @@ module TS.SpaceTac.UI {
}
let text = `${effect.getDescription()} (${effect.duration} turns)`;
- let color = effect.isBeneficial() ? "afe9c6" : "#e9afaf";
+ let color = effect.isBeneficial() ? "#afe9c6" : "#e9afaf";
let effect_text = new Phaser.Text(this.game, 60, effect_group.height / 2, text, { font: "16pt Arial", fill: color });
effect_text.anchor.set(0, 0.5);
effect_group.addChild(effect_text);