Ship tooltip now displays precision and maneuvrability
1
TODO.md
|
@ -36,7 +36,6 @@ Character sheet
|
|||
Battle
|
||||
------
|
||||
|
||||
* Display precision and maneuvrability in ship tooltip
|
||||
* Add a voluntary retreat option
|
||||
* Add scroll buttons when there are too many actions
|
||||
* Toggle bar/text display in power section of action bar
|
||||
|
|
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 5.5 KiB |
After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 323 KiB After Width: | Height: | Size: 361 KiB |
|
@ -109,6 +109,44 @@ module TK.SpaceTac.UI.Specs {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Crawn through the children of a node
|
||||
*/
|
||||
export function crawlChildren(node: UIContainer, recursive: boolean, callback: (child: any) => void): void {
|
||||
node.children.forEach(child => {
|
||||
callback(child);
|
||||
if (recursive && (child instanceof Phaser.Group || child instanceof Phaser.Image)) {
|
||||
crawlChildren(child, true, callback);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect all image codes in a node
|
||||
*/
|
||||
export function collectImages(node: UIContainer, recursive = true): (string | null)[] {
|
||||
let result: (string | null)[] = [];
|
||||
crawlChildren(node, recursive, child => {
|
||||
if (child instanceof Phaser.Image) {
|
||||
result.push(child.name || null);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect all texts in a node
|
||||
*/
|
||||
export function collectTexts(node: UIContainer, recursive = true): (string | null)[] {
|
||||
let result: (string | null)[] = [];
|
||||
crawlChildren(node, recursive, child => {
|
||||
if (child instanceof Phaser.Text) {
|
||||
result.push(child.text || null);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a given text node
|
||||
*/
|
||||
|
|
|
@ -18,21 +18,21 @@ module TK.SpaceTac.UI.Specs {
|
|||
let action3 = new EndTurnAction();
|
||||
check.patch(action3, "getVerb", () => "End turn");
|
||||
|
||||
ActionTooltip.fill(tooltip.getFiller(), ship, action1, 0);
|
||||
ActionTooltip.fill(tooltip.getBuilder(), ship, action1, 0);
|
||||
checkText(check, (<any>tooltip).container.content.children[1], "Engine");
|
||||
checkText(check, (<any>tooltip).container.content.children[2], "Cost: 1 power per 0km");
|
||||
checkText(check, (<any>tooltip).container.content.children[3], "Move: 0km per power point (safety: 120km)");
|
||||
checkText(check, (<any>tooltip).container.content.children[4], "[ 1 ]");
|
||||
|
||||
tooltip.hide();
|
||||
ActionTooltip.fill(tooltip.getFiller(), ship, action2, 1);
|
||||
ActionTooltip.fill(tooltip.getBuilder(), ship, action2, 1);
|
||||
checkText(check, (<any>tooltip).container.content.children[1], "Weapon");
|
||||
checkText(check, (<any>tooltip).container.content.children[2], "Cost: 2 power");
|
||||
checkText(check, (<any>tooltip).container.content.children[3], "Fire (power 2, range 50km):\n• do 12 damage on target");
|
||||
checkText(check, (<any>tooltip).container.content.children[4], "[ 2 ]");
|
||||
|
||||
tooltip.hide();
|
||||
ActionTooltip.fill(tooltip.getFiller(), ship, action3, 2);
|
||||
ActionTooltip.fill(tooltip.getBuilder(), ship, action3, 2);
|
||||
checkText(check, (<any>tooltip).container.content.children[1], "End turn");
|
||||
checkText(check, (<any>tooltip).container.content.children[2], "End the current ship's turn.\nWill also generate power and cool down equipments.");
|
||||
checkText(check, (<any>tooltip).container.content.children[3], "[ space ]");
|
||||
|
|
|
@ -6,7 +6,7 @@ module TK.SpaceTac.UI {
|
|||
/**
|
||||
* Fill the tooltip
|
||||
*/
|
||||
static fill(filler: TooltipFiller, ship: Ship, action: BaseAction, position: number) {
|
||||
static fill(filler: TooltipBuilder, ship: Ship, action: BaseAction, position: number) {
|
||||
let builder = filler.styled({ size: 20 });
|
||||
|
||||
let icon = builder.image([`equipment-${action.equipment ? action.equipment.code : "---"}`, `action-${action.code}`]);
|
||||
|
@ -40,17 +40,17 @@ module TK.SpaceTac.UI {
|
|||
if (action.equipment && action.equipment.cooldown.overheat) {
|
||||
let cooldown = action.equipment.cooldown;
|
||||
if (cooldown.heat > 0) {
|
||||
builder.text("Cooling down ...", 150, 80, { color: "#c9604c" });
|
||||
builder.text("Cooling down ...", 150, 80, { color: "#d8894d" });
|
||||
} else if (cooldown.willOverheat() && cost != "Not enough power") {
|
||||
if (cooldown.cooling > 1) {
|
||||
let turns = cooldown.cooling - 1;
|
||||
builder.text(`Unavailable for ${turns} turn${turns > 1 ? "s" : ""} if used`, 150, 80, { color: "#c9604c" });
|
||||
builder.text(`Unavailable for ${turns} turn${turns > 1 ? "s" : ""} if used`, 150, 80, { color: "#d8894d" });
|
||||
} else {
|
||||
builder.text("Unavailable until next turn if used", 150, 80, { color: "#c9604c" });
|
||||
builder.text("Unavailable until next turn if used", 150, 80, { color: "#d8894d" });
|
||||
}
|
||||
}
|
||||
} else if (action instanceof ToggleAction && action.activated) {
|
||||
builder.text(`Activated`, 150, 80, { color: "#c9604c" });
|
||||
builder.text(`Activated`, 150, 80, { color: "#dbe748" });
|
||||
}
|
||||
|
||||
let description = action.getEffectsDescription();
|
||||
|
|
|
@ -12,24 +12,26 @@ module TK.SpaceTac.UI.Specs {
|
|||
TestTools.setShipHP(ship, 58, 140);
|
||||
TestTools.setShipAP(ship, 12);
|
||||
TestTools.addWeapon(ship, 50);
|
||||
TestTools.setAttribute(ship, "precision", 7);
|
||||
TestTools.setAttribute(ship, "maneuvrability", 3);
|
||||
ship.setValue("hull", 57);
|
||||
ship.setValue("shield", 100);
|
||||
ship.setValue("power", 9);
|
||||
ship.active_effects.add(new AttributeEffect("hull_capacity", 50));
|
||||
ship.active_effects.add(new StickyEffect(new DamageModifierEffect(-15), 3));
|
||||
ship.active_effects.add(new AttributeLimitEffect("precision", 10));
|
||||
tooltip.setShip(ship);
|
||||
|
||||
let content = (<any>tooltip).container.content;
|
||||
check.equals(content.children[0].name, "ship-fake-portrait");
|
||||
check.equals(content.children[1].text, "Phil's Level 1 Fury");
|
||||
check.equals(content.children[2].text, "Plays in 2 turns");
|
||||
check.equals(content.children[3].text, "Hull\n58/58");
|
||||
check.equals(content.children[4].text, "Shield\n140/140");
|
||||
check.equals(content.children[5].text, "Power\n12/12");
|
||||
check.equals(content.children[6].text, "Active effects");
|
||||
check.equals(content.children[7].text, "• hull capacity +50");
|
||||
check.equals(content.children[8].text, "• damage -15% for 3 turns");
|
||||
check.equals(content.children[9].text, "• limit precision to 10");
|
||||
check.equals(content.children[10].text, "Weapons");
|
||||
check.equals(content.children[11].text, "• equipment Mk1");
|
||||
let images = collectImages((<any>tooltip).container);
|
||||
let texts = collectTexts((<any>tooltip).container);
|
||||
check.contains(images, "ship-fake-portrait");
|
||||
check.contains(images, "equipment-equipment");
|
||||
check.equals(texts, [
|
||||
"Phil's Level 1 Fury", "Plays in 2 turns",
|
||||
"7", "3", "9", "max", "12", "57", "max", "58", "100", "max", "140",
|
||||
"Active effects", "• hull capacity +50", "• damage -15% for 3 turns", "• limit precision to 10",
|
||||
"Weapons", "equipment Mk1"
|
||||
]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -19,47 +19,54 @@ module TK.SpaceTac.UI {
|
|||
setShip(ship: Ship): void {
|
||||
this.hide();
|
||||
|
||||
let filler = this.getFiller();
|
||||
let builder = this.getBuilder();
|
||||
|
||||
filler.configure(10, 6, this.battleview.arena.getBoundaries());
|
||||
builder.configure(10, 6, this.battleview.arena.getBoundaries());
|
||||
|
||||
let portrait = filler.image(`ship-${ship.model.code}-portrait`);
|
||||
portrait.scale.set(0.5);
|
||||
let portrait_bg = builder.image("battle-tooltip-ship-portrait");
|
||||
builder.in(portrait_bg, builder => {
|
||||
let portrait = builder.image(`ship-${ship.model.code}-portrait`, portrait_bg.width / 2, portrait_bg.height / 2);
|
||||
portrait.anchor.set(0.5);
|
||||
portrait.scale.set(0.5);
|
||||
});
|
||||
|
||||
let enemy = !ship.getPlayer().is(this.battleview.player);
|
||||
filler.text(ship.getFullName(), 140, 0, { color: enemy ? "#cc0d00" : "#ffffff", size: 22, bold: true });
|
||||
builder.text(ship.getFullName(), 168, 0, { color: enemy ? "#cc0d00" : "#ffffff", size: 22, bold: true });
|
||||
|
||||
if (ship.alive) {
|
||||
let turns = this.battleview.battle.getPlayOrder(ship);
|
||||
filler.text((turns == 0) ? "Playing" : ((turns == 1) ? "Plays next" : `Plays in ${turns} turns`), 140, 36, { color: "#cccccc", size: 18 });
|
||||
builder.text((turns == 0) ? "Playing" : ((turns == 1) ? "Plays next" : `Plays in ${turns} turns`), 168, 36, { color: "#cccccc", size: 18 });
|
||||
|
||||
let hsp_builder = filler.styled({ color: "#eb4e4a", size: 20, center: true, vcenter: true, bold: true });
|
||||
hsp_builder.text(`Hull\n${ship.getValue("hull")}/${ship.getAttribute("hull_capacity")}`, 200, 106, { color: "#eb4e4a" });
|
||||
hsp_builder.text(`Shield\n${ship.getValue("shield")}/${ship.getAttribute("shield_capacity")}`, 340, 106, { color: "#2ad8dc" });
|
||||
hsp_builder.text(`Power\n${ship.getValue("power")}/${ship.getAttribute("power_capacity")}`, 480, 106, { color: "#ffdd4b" });
|
||||
ShipTooltip.addValue(builder, 0, "#aa6f33", "character-attribute-precision", ship.getAttribute("precision"));
|
||||
ShipTooltip.addValue(builder, 1, "#c1f06b", "character-attribute-maneuvrability", ship.getAttribute("maneuvrability"));
|
||||
ShipTooltip.addValue(builder, 2, "#ffdd4b", "character-value-power", ship.getValue("power"), ship.getAttribute("power_capacity"));
|
||||
ShipTooltip.addValue(builder, 3, "#eb4e4a", "character-value-hull", ship.getValue("hull"), ship.getAttribute("hull_capacity"));
|
||||
ShipTooltip.addValue(builder, 4, "#2ad8dc", "character-value-shield", ship.getValue("shield"), ship.getAttribute("shield_capacity"));
|
||||
|
||||
let iy = 148;
|
||||
let iy = 170;
|
||||
let effects = ship.active_effects.list();
|
||||
if (effects.length > 0) {
|
||||
filler.text("Active effects", 0, iy, { color: "#ffffff", size: 18, bold: true });
|
||||
builder.text("Active effects", 0, iy, { color: "#ffffff", size: 18, bold: true });
|
||||
iy += 30;
|
||||
effects.forEach(effect => {
|
||||
filler.text(`• ${effect.getDescription()}`, 0, iy, { color: effect.isBeneficial() ? "#afe9c6" : "#e9afaf" });
|
||||
builder.text(`• ${effect.getDescription()}`, 0, iy, { color: effect.isBeneficial() ? "#afe9c6" : "#e9afaf" });
|
||||
iy += 26;
|
||||
});
|
||||
}
|
||||
|
||||
let weapons = ship.listEquipment(SlotType.Weapon);
|
||||
if (weapons.length > 0) {
|
||||
filler.text("Weapons", 0, iy, { size: 18, bold: true });
|
||||
builder.text("Weapons", 0, iy, { size: 18, bold: true });
|
||||
iy += 30;
|
||||
weapons.forEach(weapon => {
|
||||
filler.text(`• ${weapon.getFullName()}`, 0, iy);
|
||||
let icon = builder.image(`equipment-${weapon.code}`, 0, iy);
|
||||
icon.scale.set(0.1);
|
||||
builder.text(weapon.getFullName(), 32, iy);
|
||||
iy += 26;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
filler.text("Emergency Stasis Protocol\nship disabled", 140, 36, { color: "#a899db", size: 20, center: true, vcenter: true });
|
||||
builder.text("Emergency Stasis Protocol\nship disabled", 140, 36, { color: "#a899db", size: 20, center: true, vcenter: true });
|
||||
}
|
||||
|
||||
let sprite = this.battleview.arena.findShipSprite(ship);
|
||||
|
@ -67,5 +74,18 @@ module TK.SpaceTac.UI {
|
|||
this.container.show(sprite.frame.getBounds());
|
||||
}
|
||||
}
|
||||
|
||||
private static addValue(builder: UIBuilder, idx: number, color: string, icon: string, val: number, max?: number) {
|
||||
let bg = builder.image("battle-tooltip-ship-value", 190 + idx * 72, 110, true);
|
||||
|
||||
builder.in(bg).styled({ color: color, size: 18, center: true, vcenter: true, bold: true }, builder => {
|
||||
builder.image(icon, 0, -14, true);
|
||||
builder.text(`${val}`, 0, 28);
|
||||
if (max) {
|
||||
builder.text("max", 0, 58, { size: 10 });
|
||||
builder.text(`${max}`, 0, 72, { size: 10 });
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -200,7 +200,7 @@ module TK.SpaceTac.UI {
|
|||
/**
|
||||
* Fill a tooltip with equipment data
|
||||
*/
|
||||
fillTooltip(filler: TooltipFiller): boolean {
|
||||
fillTooltip(filler: TooltipBuilder): boolean {
|
||||
let title = this.item.getFullName();
|
||||
if (this.item.slot_type !== null) {
|
||||
title += ` (${SlotType[this.item.slot_type]})`;
|
||||
|
|
|
@ -77,13 +77,14 @@ module TK.SpaceTac.UI {
|
|||
/**
|
||||
* Functions used to fill a tooltip content
|
||||
*/
|
||||
export class TooltipFiller extends UIBuilder {
|
||||
export class TooltipBuilder extends UIBuilder {
|
||||
private container: TooltipContainer;
|
||||
|
||||
constructor(container: TooltipContainer) {
|
||||
let style = new UITextStyle();
|
||||
style.center = false;
|
||||
style.vcenter = false;
|
||||
style.shadow = true;
|
||||
super(container.view, container.content, style);
|
||||
|
||||
this.container = container;
|
||||
|
@ -118,10 +119,10 @@ module TK.SpaceTac.UI {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get a tooltip filler
|
||||
* Get a tooltip builder
|
||||
*/
|
||||
getFiller(): TooltipFiller {
|
||||
return new TooltipFiller(this.container);
|
||||
getBuilder(): TooltipBuilder {
|
||||
return new TooltipBuilder(this.container);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -129,12 +130,12 @@ module TK.SpaceTac.UI {
|
|||
*
|
||||
* When the component is hovered, the function is called to allow filling the tooltip container
|
||||
*/
|
||||
bind(obj: Phaser.Button, func: (filler: TooltipFiller) => boolean): void {
|
||||
bind(obj: Phaser.Button, func: (filler: TooltipBuilder) => boolean): void {
|
||||
this.view.inputs.setHoverClick(obj,
|
||||
// enter
|
||||
() => {
|
||||
this.hide();
|
||||
if (func(this.getFiller())) {
|
||||
if (func(this.getBuilder())) {
|
||||
this.container.show(obj.getBounds());
|
||||
}
|
||||
},
|
||||
|
|
|
@ -160,7 +160,7 @@ module TK.SpaceTac.UI {
|
|||
/**
|
||||
* Add an image
|
||||
*/
|
||||
image(name: string | string[], x = 0, y = 0): UIImage {
|
||||
image(name: string | string[], x = 0, y = 0, centered = false): UIImage {
|
||||
if (typeof name != "string") {
|
||||
name = this.view.getFirstImage(...name);
|
||||
}
|
||||
|
@ -168,6 +168,9 @@ module TK.SpaceTac.UI {
|
|||
let info = this.view.getImageInfo(name);
|
||||
let result = this.game.add.image(x, y, info.key, info.frame);
|
||||
result.name = name;
|
||||
if (centered) {
|
||||
result.anchor.set(0.5)
|
||||
}
|
||||
this.add(result);
|
||||
return result;
|
||||
}
|
||||
|
|