1
0
Fork 0

Display ship values variations in arena

This commit is contained in:
Michaël Lemaire 2017-02-12 23:18:36 +01:00
parent 7b8074a5ae
commit e5cd71f4e1
15 changed files with 118 additions and 85 deletions

View file

@ -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): 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 * **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) * **Power** - Available action points (some actions require more power than others)
These values will be changed by various effects (usage of equipments, sustained damage...). 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
Attributes represent a ship's ability to use its HSP system: 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 and "energy >= 3" to be equipped. A ship that does not meet these requirements will not be able to use
the equipment. 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 If an equipped item has a requirement of "time skill >= 2", that the ship has "time skill" of exactly 2, and
temporary effect of "time -1" is active, the requirement is no longer fulfilled and the equipped item that a temporary effect of "time skill -1" is active, the requirement is no longer fulfilled and the equipped
is then temporarily disabled (no more effects and cannot be used), until the "time -1" effect is lifted. item is then temporarily disabled (no more effects and cannot be used), until the "time skill -1" effect is lifted.
## Drones ## Drones

3
TODO
View file

@ -1,10 +1,11 @@
* Drones: add tooltip * Drones: add tooltip
* Drones: add hull points and take area damage * Drones: add hull points and take area damage
* Drones: change the sprite angle for deploy animation * Drones: change the sprite angle for deploy animation
* Better display of effects over ship sprite (repairs, sticky effects...)
* Add a battle log display * Add a battle log display
* Organize arena objects and information in layers * 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 * Allow to cancel last moves
* Identify ships in emergency stasis more clearly
* Add more visual effects to weapons, hits and explosions * Add more visual effects to weapons, hits and explosions
* Effect should be random in a range (eg. "damage target 50-75") * Effect should be random in a range (eg. "damage target 50-75")
* Add an overload/cooling system * Add an overload/cooling system

Binary file not shown.

After

Width:  |  Height:  |  Size: 9 KiB

View file

@ -107,8 +107,8 @@ module TS.SpaceTac.Specs {
expect(ship.values.hull.get()).toEqual(40); expect(ship.values.hull.get()).toEqual(40);
expect(ship.values.shield.get()).toEqual(80); expect(ship.values.shield.get()).toEqual(80);
expect(battle.log.events.length).toBe(3); expect(battle.log.events.length).toBe(3);
expect(battle.log.events[0]).toEqual(new ValueChangeEvent(ship, ship.values.shield)); 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)); expect(battle.log.events[1]).toEqual(new ValueChangeEvent(ship, ship.values.hull, -10));
expect(battle.log.events[2]).toEqual(new DamageEvent(ship, 10, 20)); expect(battle.log.events[2]).toEqual(new DamageEvent(ship, 10, 20));
battle.log.clear(); battle.log.clear();

View file

@ -195,20 +195,20 @@ module TS.SpaceTac {
* Returns true if the value changed. * Returns true if the value changed.
*/ */
setValue(name: keyof ShipValues, value: number, offset = false, log = true): boolean { setValue(name: keyof ShipValues, value: number, offset = false, log = true): boolean {
let changed: boolean; let diff = 0;
let val = this.values[name]; let val = this.values[name];
if (offset) { if (offset) {
changed = val.add(value); diff = val.add(value);
} else { } else {
changed = val.set(value); diff = val.set(value);
} }
if (changed && log) { if (log && diff != 0) {
this.addBattleEvent(new ValueChangeEvent(this, val)); 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. * Returns true if the value changed.
*/ */
setAttribute(name: keyof ShipAttributes, value: number, log = true): boolean { setAttribute(name: keyof ShipAttributes, value: number, log = true): boolean {
let changed: boolean;
let attr = this.attributes[name]; let attr = this.attributes[name];
let diff = attr.set(value);
changed = attr.set(value);
// TODO more generic // TODO more generic
if (name == "power_capacity") { if (name == "power_capacity") {
@ -240,11 +238,11 @@ module TS.SpaceTac {
this.values.hull.setMaximal(attr.get()); this.values.hull.setMaximal(attr.get());
} }
if (changed && log) { if (log && diff != 0) {
this.addBattleEvent(new ValueChangeEvent(this, attr)); this.addBattleEvent(new ValueChangeEvent(this, attr, diff));
} }
return changed; return diff != 0;
} }
// Initialize the action points counter // Initialize the action points counter

View file

@ -39,34 +39,34 @@ module TS.SpaceTac {
expect(attr.get()).toBe(50); expect(attr.get()).toBe(50);
}); });
it("tells if value changed", function () { it("tells the value variation", function () {
var result: boolean; var result: number;
var attr = new ShipValue("test", 50, 100); var attr = new ShipValue("test", 50, 100);
expect(attr.get()).toBe(50); expect(attr.get()).toBe(50);
result = attr.set(51); result = attr.set(51);
expect(result).toBe(true); expect(result).toBe(1);
result = attr.set(51); result = attr.set(51);
expect(result).toBe(false); expect(result).toBe(0);
result = attr.add(1); result = attr.add(1);
expect(result).toBe(true); expect(result).toBe(1);
result = attr.add(0); result = attr.add(0);
expect(result).toBe(false); expect(result).toBe(0);
result = attr.add(1000); result = attr.add(1000);
expect(result).toBe(true); expect(result).toBe(48);
result = attr.add(2000); result = attr.add(2000);
expect(result).toBe(false); expect(result).toBe(0);
result = attr.set(-500); result = attr.set(-500);
expect(result).toBe(true); expect(result).toBe(-100);
result = attr.add(-600); result = attr.add(-600);
expect(result).toBe(false); expect(result).toBe(0);
}); });
}); });
} }

View file

@ -36,13 +36,13 @@ module TS.SpaceTac {
/** /**
* Set an absolute value * 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; var old_value = this.current;
this.current = value; this.current = value;
this.fix(); 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 * Returns true if the value changed
*/ */
add(value: number): boolean { add(value: number): number {
var old_value = this.current; var old_value = this.current;
this.current += value; this.current += value;
this.fix(); this.fix();
return this.current !== old_value; return this.current - old_value;
} }
/** /**

View file

@ -235,17 +235,13 @@ module TS.SpaceTac.Specs {
expect(battle.log.events.length).toBe(7); expect(battle.log.events.length).toBe(7);
expect(battle.log.events[0]).toEqual(new MoveEvent(ship1, 2, 0)); expect(battle.log.events[0]).toEqual(new MoveEvent(ship1, 2, 0));
expect(battle.log.events[1]).toEqual(new ValueChangeEvent(ship1, expect(battle.log.events[1]).toEqual(new ValueChangeEvent(ship1, new ShipValue("power", 2, 10), -4));
new ShipValue("power", 2, 10)));
expect(battle.log.events[2]).toEqual(new FireEvent(ship1, weapon, Target.newFromShip(ship2))); expect(battle.log.events[2]).toEqual(new FireEvent(ship1, weapon, Target.newFromShip(ship2)));
expect(battle.log.events[3]).toEqual(new ValueChangeEvent(ship2, expect(battle.log.events[3]).toEqual(new ValueChangeEvent(ship2, new ShipValue("shield", 0), -10));
new ShipValue("shield", 0))); expect(battle.log.events[4]).toEqual(new ValueChangeEvent(ship2, new ShipValue("hull", 5), -10));
expect(battle.log.events[4]).toEqual(new ValueChangeEvent(ship2,
new ShipValue("hull", 5)));
expect(battle.log.events[5]).toEqual(new DamageEvent(ship2, 10, 10)); expect(battle.log.events[5]).toEqual(new DamageEvent(ship2, 10, 10));
expect(battle.log.events[6]).toEqual(new ValueChangeEvent(ship1, expect(battle.log.events[6]).toEqual(new ValueChangeEvent(ship1, new ShipValue("power", 1, 10), -1));
new ShipValue("power", 1, 10)));
}); });
}); });
} }

View file

@ -3,13 +3,17 @@
module TS.SpaceTac { module TS.SpaceTac {
// Event logged when a ship value or attribute changed // Event logged when a ship value or attribute changed
export class ValueChangeEvent extends BaseLogEvent { export class ValueChangeEvent extends BaseLogEvent {
// Saved version of the value // Saved version of the current value
value: ShipValue; value: ShipValue;
constructor(ship: Ship, value: ShipValue) { // Value variation
diff: number;
constructor(ship: Ship, value: ShipValue, diff: number) {
super("value", ship); super("value", ship);
this.value = copy(value); this.value = copy(value);
this.diff = diff;
} }
} }
} }

View file

@ -56,6 +56,7 @@ module TS.SpaceTac.UI {
this.loadImage("battle/actions/deploy-repairdrone.png"); this.loadImage("battle/actions/deploy-repairdrone.png");
this.loadImage("battle/weapon/bullet.png"); this.loadImage("battle/weapon/bullet.png");
this.loadImage("battle/attributes/power.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-increase.png");
this.loadImage("battle/attributes/effect-decrease.png"); this.loadImage("battle/attributes/effect-decrease.png");
this.loadImage("battle/attributes/effect-limit.png"); this.loadImage("battle/attributes/effect-limit.png");

View file

@ -2,6 +2,9 @@ module TS.SpaceTac.UI {
// Graphical representation of a battle // Graphical representation of a battle
// This is the area in the BattleView that will display ships with their real positions // This is the area in the BattleView that will display ships with their real positions
export class Arena extends Phaser.Group { export class Arena extends Phaser.Group {
// Link to battleview
battleview: BattleView;
// Arena background // Arena background
background: Phaser.Button; background: Phaser.Button;
@ -11,9 +14,6 @@ module TS.SpaceTac.UI {
// Input callback to receive mouse move events // Input callback to receive mouse move events
private input_callback: any; private input_callback: any;
// Link to battleview
private battleview: BattleView;
// List of ship sprites // List of ship sprites
private ship_sprites: ArenaShip[] = []; private ship_sprites: ArenaShip[] = [];
@ -75,8 +75,8 @@ module TS.SpaceTac.UI {
// Initialize state (create sprites) // Initialize state (create sprites)
init(): void { init(): void {
// Add ship sprites // Add ship sprites
this.battleview.battle.play_order.forEach((ship: Ship) => { this.battleview.battle.play_order.forEach(ship => {
var sprite = new ArenaShip(this.battleview, ship); var sprite = new ArenaShip(this, ship);
this.addChild(sprite); this.addChild(sprite);
this.ship_sprites.push(sprite); this.ship_sprites.push(sprite);
}); });
@ -92,6 +92,7 @@ module TS.SpaceTac.UI {
var sprite = this.findShipSprite(ship); var sprite = this.findShipSprite(ship);
if (sprite) { if (sprite) {
sprite.alpha = 0.5; sprite.alpha = 0.5;
sprite.displayEffect("Emergency Stasis", false);
} }
} }

View file

@ -0,0 +1,24 @@
/// <reference path="../TestGame.ts"/>
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 = <Phaser.Text>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 = <Phaser.Text>sprite.effects.getChildAt(1);
expect(t2.text).toBe("shield +12");
});
});
}

View file

@ -16,30 +16,38 @@ module TS.SpaceTac.UI {
// Frame to indicate the owner of the ship, and if it is playing // Frame to indicate the owner of the ship, and if it is playing
frame: Phaser.Image; frame: Phaser.Image;
// Effects display
effects: Phaser.Group;
// Create a ship sprite usable in the Arena // Create a ship sprite usable in the Arena
constructor(battleview: BattleView, ship: Ship) { constructor(parent: Arena, ship: Ship) {
super(battleview.game); super(parent.game);
let battleview = parent.battleview;
this.ship = ship; this.ship = ship;
this.enemy = this.ship.getPlayer() != battleview.player; this.enemy = this.ship.getPlayer() != battleview.player;
// Add ship sprite // 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.rotation = ship.arena_angle;
this.sprite.anchor.set(0.5, 0.5); this.sprite.anchor.set(0.5, 0.5);
this.addChild(this.sprite); this.addChild(this.sprite);
// Add playing effect // 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.frame.anchor.set(0.5, 0.5);
this.addChild(this.frame); this.addChild(this.frame);
// Add hover effect // 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.anchor.set(0.5, 0.5);
this.hover.visible = false; this.hover.visible = false;
this.addChild(this.hover); this.addChild(this.hover);
// Effects display
this.effects = new Phaser.Group(this.game);
this.addChild(this.effects);
// Handle input on ship sprite // Handle input on ship sprite
Tools.setHoverClick(this.sprite, () => battleview.cursorOnShip(ship), () => battleview.cursorOffShip(ship), () => battleview.cursorClicked()); 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) { * Briefly show an effect on this ship
if (hull > 0) { */
var hull_text = new Phaser.Text(this.game, -20, -20, Math.round(hull).toString(), displayEffect(message: string, beneficial: boolean) {
{ font: "bold 16pt Arial", align: "center", fill: "#eb4e4a" }); let text = new Phaser.Text(this.game, 0, 20 * this.effects.children.length, message, { font: "14pt Arial", fill: beneficial ? "#afe9c6" : "#e9afaf" });
hull_text.anchor.set(0.5, 0.5); this.effects.addChild(text);
this.addChild(hull_text);
this.animateDamageText(hull_text); this.effects.position.set(-this.effects.width / 2, this.sprite.height * 0.7);
}
if (shield > 0) { this.game.tweens.removeFrom(this.effects);
var shield_text = new Phaser.Text(this.game, 20, -20, Math.round(shield).toString(), this.effects.alpha = 1;
{ font: "bold 16pt Arial", align: "center", fill: "#2ad8dc" }); let tween = this.game.tweens.create(this.effects).to({ alpha: 0 }, 500).delay(1000).start();
shield_text.anchor.set(0.5, 0.5); tween.onComplete.addOnce(() => this.effects.removeAll(true));
this.addChild(shield_text);
this.animateDamageText(shield_text);
}
} }
private animateDamageText(text: Phaser.Text) { /**
text.alpha = 0; * Display interesting changes in ship values
var tween = this.game.tweens.create(text); */
tween.to({ alpha: 1 }, 100, Phaser.Easing.Circular.In, false, 400); displayValueChanged(event: ValueChangeEvent) {
tween.to({ y: -50, alpha: 0 }, 1000, Phaser.Easing.Circular.In, false, 1000); let diff = event.diff;
tween.onComplete.addOnce(() => { let name = event.value.name;
text.destroy(); this.displayEffect(`${name} ${diff < 0 ? "-" : "+"}${Math.abs(diff)}`, diff >= 0);
});
tween.start();
} }
} }
} }

View file

@ -72,10 +72,6 @@ module TS.SpaceTac.UI {
// Damage to ship // Damage to ship
private processDamageEvent(event: DamageEvent): void { 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); var item = this.view.ship_list.findItem(event.ship);
if (item) { if (item) {
item.setDamageHit(); item.setDamageHit();
@ -92,10 +88,14 @@ module TS.SpaceTac.UI {
// Ship value changed // Ship value changed
private processValueChangedEvent(event: ValueChangeEvent): void { 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); var item = this.view.ship_list.findItem(event.ship);
if (item) { if (item) {
item.updateAttributes(); item.updateAttributes();
} }
// TODO Update tooltip // TODO Update tooltip
} }

View file

@ -136,7 +136,7 @@ module TS.SpaceTac.UI {
} }
let text = `${effect.getDescription()} (${effect.duration} turns)`; 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 }); 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_text.anchor.set(0, 0.5);
effect_group.addChild(effect_text); effect_group.addChild(effect_text);