Display ship values variations in arena
This commit is contained in:
parent
7b8074a5ae
commit
e5cd71f4e1
15
README.md
15
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
|
||||
|
||||
|
|
3
TODO
3
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
|
||||
|
|
BIN
out/assets/images/battle/attributes/powercapacity.png
Normal file
BIN
out/assets/images/battle/attributes/powercapacity.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9 KiB |
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
24
src/ui/battle/ArenaShip.spec.ts
Normal file
24
src/ui/battle/ArenaShip.spec.ts
Normal 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");
|
||||
});
|
||||
});
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue