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):
* **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

3
TODO
View file

@ -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

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.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();

View file

@ -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

View file

@ -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);
});
});
}

View file

@ -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;
}
/**

View file

@ -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));
});
});
}

View file

@ -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;
}
}
}

View file

@ -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");

View file

@ -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);
}
}

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: 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);
}
}
}

View file

@ -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
}

View file

@ -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);