1
0
Fork 0

battleview: New ship tooltip

This commit is contained in:
Michaël Lemaire 2017-05-15 01:00:36 +02:00
parent 040de7a71b
commit 019cb73c7e
25 changed files with 171 additions and 185 deletions

2
TODO
View file

@ -5,6 +5,7 @@
* Character sheet: highlight allowed destinations during drag-and-drop, with text hints
* Character sheet: when transferring to another ship, if the item can't be equipped (unmatched requirements), the transfer is cancelled instead of trying cargo
* Character sheet: effective skill is sometimes not updated when upgrading base skill
* Character sheet: tooltip to show the sources of attributes
* Menu: end appear animation when a button is clicked
* Menu: allow to delete cloud saves
* Menu: fix background stars aggregating at right side when the game is not focused
@ -27,7 +28,6 @@
* Add an overheat/cooling system
* Add auto-move to attack
* Merge identical sticky effects
* Handle effects overflowing ship tooltip when too numerous
* Allow to skip animations and AI delays in battle
* Mobile: think UI layout so that fingers do not block the view (right and left handed)
* Mobile: display tooltips larger and on the side of screen where the finger is not

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 418 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 475 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 542 B

View file

@ -300,5 +300,36 @@ module TS.SpaceTac {
expect(battle.canPlay(player)).toBe(true);
});
it("gets the number of turns before a specific ship plays", function () {
let battle = new Battle();
spyOn(battle, "checkEndBattle").and.returnValue(false);
battle.play_order = [new Ship(), new Ship(), new Ship()];
battle.advanceToNextShip();
expect(battle.playing_ship).toBe(battle.play_order[0]);
expect(battle.getTurnsBefore(battle.play_order[0])).toBe(0);
expect(battle.getTurnsBefore(battle.play_order[1])).toBe(1);
expect(battle.getTurnsBefore(battle.play_order[2])).toBe(2);
battle.advanceToNextShip();
expect(battle.playing_ship).toBe(battle.play_order[1]);
expect(battle.getTurnsBefore(battle.play_order[0])).toBe(2);
expect(battle.getTurnsBefore(battle.play_order[1])).toBe(0);
expect(battle.getTurnsBefore(battle.play_order[2])).toBe(1);
battle.advanceToNextShip();
expect(battle.getTurnsBefore(battle.play_order[0])).toBe(1);
expect(battle.getTurnsBefore(battle.play_order[1])).toBe(2);
expect(battle.getTurnsBefore(battle.play_order[2])).toBe(0);
battle.advanceToNextShip();
expect(battle.getTurnsBefore(battle.play_order[0])).toBe(0);
expect(battle.getTurnsBefore(battle.play_order[1])).toBe(1);
expect(battle.getTurnsBefore(battle.play_order[2])).toBe(2);
});
});
}

View file

@ -68,6 +68,17 @@ module TS.SpaceTac {
return this.play_order.length;
}
/**
* Get the number of turns before a specific ship plays (currently playing ship will return 0).
*/
getTurnsBefore(ship: Ship): number {
let pos = this.play_order.indexOf(ship) - (this.playing_ship_index || 0);
if (pos < 0) {
pos += this.play_order.length;
}
return pos;
}
/**
* Return an iterator over all ships engaged in the battle
*/

View file

@ -19,6 +19,7 @@ module TS.SpaceTac.UI {
timer: Timer;
// Tooltip
tooltip_layer: Phaser.Group;
tooltip: Tooltip;
// Layers
@ -59,6 +60,7 @@ module TS.SpaceTac.UI {
this.inputs = new InputManager(this);
// Tooltip
this.tooltip_layer = this.add.group();
this.tooltip = new Tooltip(this);
// Browser console variable (for debugging purpose)

View file

@ -38,10 +38,6 @@ module TS.SpaceTac.UI {
this.loadImage("battle/power-available.png");
this.loadImage("battle/power-using.png");
this.loadImage("battle/power-used.png");
this.loadImage("battle/ship-tooltip-own.png");
this.loadImage("battle/ship-tooltip-enemy.png");
this.loadImage("battle/ship-tooltip-effect.png");
this.loadImage("battle/ship-tooltip-stasis.png");
this.loadImage("battle/arena/ship-hover.png");
this.loadImage("battle/arena/ship-normal-enemy.png");
this.loadImage("battle/arena/ship-normal-own.png");
@ -61,15 +57,6 @@ module TS.SpaceTac.UI {
this.loadImage("battle/weapon/hot.png");
this.loadImage("battle/weapon/shield-impact.png");
this.loadImage("battle/weapon/blast.png");
this.loadImage("battle/attributes/power.png");
this.loadImage("battle/attributes/powercapacity.png");
this.loadImage("battle/attributes/hull.png");
this.loadImage("battle/attributes/hullcapacity.png");
this.loadImage("battle/attributes/shield.png");
this.loadImage("battle/attributes/shieldcapacity.png");
this.loadImage("battle/attributes/effect-increase.png");
this.loadImage("battle/attributes/effect-decrease.png");
this.loadImage("battle/attributes/effect-limit.png");
this.loadImage("battle/outcome/dialog.png");
this.loadImage("battle/outcome/title-victory.png");
this.loadImage("battle/outcome/title-defeat.png");

View file

@ -92,7 +92,6 @@ module TS.SpaceTac.UI {
this.action_bar = new ActionBar(this);
this.ship_list = new ShipList(this);
this.ship_tooltip = new ShipTooltip(this);
this.layer_overlay.add(this.ship_tooltip);
this.outcome_layer = new Phaser.Group(this.game);
this.layer_dialogs.add(this.outcome_layer);
this.character_sheet = new CharacterSheet(this, -this.getWidth());
@ -192,7 +191,13 @@ module TS.SpaceTac.UI {
this.ship_hovered = ship;
this.arena.setShipHovered(ship);
this.ship_list.setHovered(ship);
this.ship_tooltip.setShip(ship);
if (ship) {
this.ship_tooltip.setShip(ship);
} else {
this.ship_tooltip.hide();
}
if (this.targetting) {
if (ship) {
this.targetting.setTargetShip(ship);

View file

@ -1,171 +1,80 @@
/// <reference path="../common/Tooltip.ts" />
module TS.SpaceTac.UI {
// Tooltip to display ship information
export class ShipTooltip extends Phaser.Group {
battleview: BattleView;
background: Phaser.Image;
title: Phaser.Text;
attr_hull: Phaser.Text;
attr_shield: Phaser.Text;
attr_power: Phaser.Text;
attr_materials: Phaser.Text;
attr_electronics: Phaser.Text;
attr_energy: Phaser.Text;
attr_human: Phaser.Text;
attr_gravity: Phaser.Text;
attr_time: Phaser.Text;
active_effects: Phaser.Group;
stasis: Phaser.Image;
/**
* Tooltip to display ship information on hover
*/
export class ShipTooltip extends Tooltip {
battleview: BattleView
constructor(parent: BattleView) {
super(parent.game);
this.visible = false;
super(parent);
this.battleview = parent;
this.background = new Phaser.Image(this.game, 0, 0, "battle-ship-tooltip-own");
this.addChild(this.background);
this.title = new Phaser.Text(this.game, 250, 10, "", { font: "24pt Arial", fill: "#ffffff" });
this.title.anchor.set(0.5, 0);
this.addChild(this.title);
this.attr_hull = new Phaser.Text(this.game, 97, 86, "", { font: "18pt Arial", fill: "#eb4e4a", fontWeight: "bold" });
this.attr_hull.anchor.set(0.5, 0.5);
this.addChild(this.attr_hull);
this.attr_shield = new Phaser.Text(this.game, 250, 86, "", { font: "18pt Arial", fill: "#2ad8dc", fontWeight: "bold" });
this.attr_shield.anchor.set(0.5, 0.5);
this.addChild(this.attr_shield);
this.attr_power = new Phaser.Text(this.game, 397, 86, "", { font: "18pt Arial", fill: "#ffdd4b", fontWeight: "bold" });
this.attr_power.anchor.set(0.5, 0.5);
this.addChild(this.attr_power);
this.attr_materials = new Phaser.Text(this.game, 217, 149, "", { font: "14pt Arial", fill: "#d5d5ff", fontWeight: "bold" });
this.attr_materials.anchor.set(0.5, 0.5);
this.addChild(this.attr_materials);
this.attr_electronics = new Phaser.Text(this.game, 447, 149, "", { font: "14pt Arial", fill: "#d5d5ff", fontWeight: "bold" });
this.attr_electronics.anchor.set(0.5, 0.5);
this.addChild(this.attr_electronics);
this.attr_energy = new Phaser.Text(this.game, 217, 176, "", { font: "14pt Arial", fill: "#d5d5ff", fontWeight: "bold" });
this.attr_energy.anchor.set(0.5, 0.5);
this.addChild(this.attr_energy);
this.attr_human = new Phaser.Text(this.game, 447, 176, "", { font: "14pt Arial", fill: "#d5d5ff", fontWeight: "bold" });
this.attr_human.anchor.set(0.5, 0.5);
this.addChild(this.attr_human);
this.attr_gravity = new Phaser.Text(this.game, 447, 203, "", { font: "14pt Arial", fill: "#d5d5ff", fontWeight: "bold" });
this.attr_gravity.anchor.set(0.5, 0.5);
this.addChild(this.attr_gravity);
this.attr_time = new Phaser.Text(this.game, 217, 203, "", { font: "14pt Arial", fill: "#d5d5ff", fontWeight: "bold" });
this.attr_time.anchor.set(0.5, 0.5);
this.addChild(this.attr_time);
this.stasis = new Phaser.Image(this.game, 16, 55, "battle-ship-tooltip-stasis");
this.stasis.visible = false;
this.addChild(this.stasis);
this.active_effects = new Phaser.Group(this.game);
this.addChild(this.active_effects);
}
// Set current ship to display, null to hide
setShip(ship: Ship | null): void {
if (ship) {
var enemy = ship.getPlayer() != this.battleview.player;
this.background.loadTexture(`battle-ship-tooltip-${enemy ? "enemy" : "own"}`);
/**
* Find ship sprite in the arena, to position next to it
*/
getPosition(ship: Ship): [number, number] {
let sprite = this.battleview.arena.findShipSprite(ship);
if (sprite) {
var x = sprite.worldPosition.x + sprite.width * sprite.worldScale.x * 0.5;
var y = sprite.worldPosition.y - sprite.height * sprite.worldScale.y * 0.5;
return [x, y];
} else {
return [0, 0];
}
}
// Find ship sprite to position next to it
var sprite = this.battleview.arena.findShipSprite(ship);
if (sprite) {
var x = sprite.worldPosition.x + sprite.width * sprite.worldScale.x * 0.5;
var y = sprite.worldPosition.y - sprite.height * sprite.worldScale.y * 0.5;
if (y + this.height > this.battleview.getHeight()) {
y = this.battleview.getHeight() - this.height;
}
if (y < 0) {
y = 0;
}
if (x + this.width > this.battleview.getWidth()) {
x = sprite.worldPosition.x - sprite.width * sprite.worldScale.x * 0.5 - this.width;
}
this.position.set(x, y);
} else {
this.position.set(0, 0);
/**
* Set the current ship to display
*/
setShip(ship: Ship): void {
this.hide();
let filler = this.getFiller();
filler.addImage(0, 0, `ship-${ship.model.code}-portrait`, 0.5);
let enemy = ship.getPlayer() != this.battleview.player;
filler.addText(140, 0, ship.name, enemy ? "#cc0d00" : "#ffffff", 22, false, true);
if (ship.alive) {
let turns = this.battleview.battle.getTurnsBefore(ship);
filler.addText(140, 36, (turns == 0) ? "Playing" : ((turns == 1) ? "Plays next" : `Plays in ${turns} turns`), "#cccccc", 18);
filler.addText(140, 72, `Hull\n${ship.getValue("hull")}`, "#eb4e4a", 20, true, true);
filler.addText(228, 72, `Shield\n${ship.getValue("shield")}`, "#2ad8dc", 20, true, true);
filler.addText(328, 72, `Power\n${ship.getValue("power")}`, "#ffdd4b", 20, true, true);
let iy = 148;
let effects = ship.sticky_effects;
if (effects.length > 0) {
filler.addText(0, iy, "Active effects", "#ffffff", 18, false, true);
iy += 30;
effects.forEach(effect => {
filler.addText(0, iy, `${effect.getDescription()}`, effect.isBeneficial() ? "#afe9c6" : "#e9afaf", 16);
iy += 26;
});
}
// Fill info
this.title.setText(ship.name);
this.attr_hull.setText(ship.values.hull.get().toString());
this.attr_shield.setText(ship.values.shield.get().toString());
this.attr_power.setText(ship.values.power.get().toString());
this.attr_materials.setText(ship.attributes.skill_material.get().toString());
this.attr_electronics.setText(ship.attributes.skill_electronics.get().toString());
this.attr_energy.setText(ship.attributes.skill_energy.get().toString());
this.attr_human.setText(ship.attributes.skill_human.get().toString());
this.attr_gravity.setText(ship.attributes.skill_gravity.get().toString());
this.attr_time.setText(ship.attributes.skill_time.get().toString());
this.active_effects.removeAll(true);
ship.sticky_effects.forEach((effect, index) => {
this.addEffect(effect, index);
});
ship.listEquipment(SlotType.Weapon).forEach((equipment, index) => {
this.addEquipment(equipment, ship.sticky_effects.length + index);
});
this.stasis.visible = !ship.alive;
this.battleview.animations.show(this, 200);
let weapons = ship.listEquipment(SlotType.Weapon);
if (weapons.length > 0) {
filler.addText(0, iy, "Weapons", "#ffffff", 18, false, true);
iy += 30;
weapons.forEach(weapon => {
filler.addText(0, iy, `${weapon.getFullName()}`, "#ffffff", 16);
iy += 26;
});
}
} else {
this.battleview.animations.hide(this, 200);
}
}
/**
* Add a sticky effect display
*/
addEffect(effect: StickyEffect, index = 0) {
let effect_group = new Phaser.Image(this.game, 27, 243 + 60 * index, "battle-ship-tooltip-effect");
this.active_effects.addChild(effect_group);
if (effect.base instanceof AttributeLimitEffect) {
let attr_name = effect.base.attrcode.replace('_', '');
let attr_icon = new Phaser.Image(this.game, 30, effect_group.height / 2, `battle-attributes-${attr_name}`);
attr_icon.anchor.set(0.5, 0.5);
attr_icon.scale.set(0.17, 0.17);
effect_group.addChild(attr_icon);
let effect_icon = new Phaser.Image(this.game, 30, effect_group.height / 2, "battle-attributes-effect-limit");
effect_icon.anchor.set(0.5, 0.5);
effect_icon.scale.set(0.17, 0.17);
effect_group.addChild(effect_icon);
filler.addText(140, 36, "Emergency Stasis Protocol\nship disabled", "#a899db", 20, true, true);
}
let text = `${effect.getDescription()} (${effect.duration} turns)`;
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);
}
/**
* Add an equipment action display
*/
addEquipment(equipment: Equipment, index = 0) {
let effect_group = new Phaser.Image(this.game, 27, 243 + 60 * index, "battle-ship-tooltip-effect");
this.active_effects.addChild(effect_group);
let effect_icon = new Phaser.Image(this.game, 30, effect_group.height / 2, `battle-actions-${equipment.action.code}`);
effect_icon.anchor.set(0.5, 0.5);
effect_icon.scale.set(0.17, 0.17);
effect_group.addChild(effect_icon);
let effect_text = new Phaser.Text(this.game, 60, effect_group.height / 2, equipment.name, { font: "16pt Arial", fill: "#ffffff" });
effect_text.anchor.set(0, 0.5);
effect_group.addChild(effect_text);
let [x, y] = this.getPosition(ship);
this.container.show(x, y);
}
}
}

View file

@ -48,7 +48,7 @@ module TS.SpaceTac.UI {
this.setupDragDrop(sheet);
this.snapToContainer();
sheet.view.tooltip.bind(this, container => this.fillTooltip(container));
sheet.view.tooltip.bind(this, filler => this.fillTooltip(filler));
}
jasmineToString() {
@ -156,9 +156,9 @@ module TS.SpaceTac.UI {
/**
* Fill a tooltip with equipment data
*/
fillTooltip(container: Phaser.Group): boolean {
container.add(new Phaser.Text(container.game, 0, 0, this.item.getFullName(), { font: "bold 20pt Arial", fill: "#cccccc" }));
container.add(new Phaser.Text(container.game, 0, 40, this.item.getFullDescription(), { font: "18pt Arial", fill: "#cccccc" }));
fillTooltip(filler: TooltipFiller): boolean {
filler.addText(0, 0, this.item.getFullName(), "#cccccc", 20, false, true);
filler.addText(0, 40, this.item.getFullDescription(), "#cccccc", 18);
return true;
}
}

View file

@ -7,9 +7,8 @@ module TS.SpaceTac.UI.Specs {
spyOn(button, "getBounds").and.returnValue({ x: 100, y: 50, width: 50, height: 25 });
let tooltip = new Tooltip(testgame.baseview);
tooltip.bind(button, container => {
let image = new Phaser.Image(testgame.ui, 22, 12, "fake");
container.add(image);
tooltip.bind(button, filler => {
filler.addImage(22, 12, "fake");
return true;
});

View file

@ -17,6 +17,8 @@ module TS.SpaceTac.UI {
this.content = new Phaser.Group(this.game);
this.add(this.content);
this.view.tooltip_layer.add(this);
}
show(x: number, y: number) {
@ -50,29 +52,69 @@ module TS.SpaceTac.UI {
}
}
/**
* Functions used to fill a tooltip content
*/
export class TooltipFiller {
private container: TooltipContainer;
constructor(container: TooltipContainer) {
this.container = container;
}
/**
* Add an image to the content
*/
addImage(x: number, y: number, key: string, scale = 1) {
let image = new Phaser.Image(this.container.game, x, y, key);
image.scale.set(scale);
this.container.content.add(image);
}
/**
* Add a text to the content
*/
addText(x: number, y: number, content: string, color = "#ffffff", size = 16, center = false, bold = false) {
let style = { font: `${bold ? "bold " : ""}${size}pt Arial`, fill: color, align: center ? "center" : "left" };
let text = new Phaser.Text(this.container.game, x, y, content, style);
this.container.content.add(text);
}
}
/**
* Tooltip system, to display information on hover
*/
export class Tooltip {
private view: BaseView;
private container: TooltipContainer;
protected view: BaseView;
protected container: TooltipContainer;
constructor(view: BaseView) {
this.view = view;
this.container = new TooltipContainer(view);
}
get ui(): MainUI {
return this.view.gameui;
}
/**
* Get a tooltip filler
*/
getFiller(): TooltipFiller {
return new TooltipFiller(this.container);
}
/**
* Bind to an UI component
*
* When the component is hovered, the function is called to allow filling the tooltip container
*/
bind(obj: Phaser.Button, func: (container: Phaser.Group) => boolean): void {
bind(obj: Phaser.Button, func: (filler: TooltipFiller) => boolean): void {
UITools.setHoverClick(obj,
// enter
() => {
this.hide();
if (func(this.container.content)) {
if (func(this.getFiller())) {
let bounds = obj.getBounds();
this.container.show(bounds.x + bounds.width + 4, bounds.y + bounds.height + 4);
}
@ -89,10 +131,10 @@ module TS.SpaceTac.UI {
* Bind to an UI component to display a dynamic text
*/
bindDynamicText(obj: Phaser.Button, text_getter: () => string): void {
this.bind(obj, container => {
this.bind(obj, filler => {
let content = text_getter();
if (content) {
container.add(new Phaser.Text(container.game, 0, 0, content, { font: "bold 20pt Arial", fill: "#cccccc" }));
filler.addText(0, 0, content, "#cccccc", 20, false, true);
return true;
} else {
return false;