2017-02-27 23:36:12 +00:00
|
|
|
module TS.SpaceTac.UI {
|
2017-03-05 23:29:02 +00:00
|
|
|
export type CharacterEquipmentDrop = {
|
|
|
|
message: string
|
|
|
|
callback: (equipment: Equipment) => any
|
|
|
|
}
|
|
|
|
|
2017-02-27 23:36:12 +00:00
|
|
|
/**
|
|
|
|
* Character sheet, displaying ship characteristics
|
|
|
|
*/
|
|
|
|
export class CharacterSheet extends Phaser.Image {
|
2017-03-15 21:40:19 +00:00
|
|
|
// Parent view
|
|
|
|
view: BaseView;
|
|
|
|
|
2017-02-28 00:07:37 +00:00
|
|
|
// X positions
|
|
|
|
xshown: number;
|
|
|
|
xhidden: number;
|
|
|
|
|
2017-02-27 23:36:12 +00:00
|
|
|
// Currently displayed fleet
|
|
|
|
fleet: Fleet;
|
|
|
|
|
|
|
|
// Currently displayed ship
|
|
|
|
ship: Ship;
|
|
|
|
|
|
|
|
// Ship name
|
|
|
|
ship_name: Phaser.Text;
|
|
|
|
|
|
|
|
// Ship level
|
|
|
|
ship_level: Phaser.Text;
|
|
|
|
|
2017-03-17 00:07:00 +00:00
|
|
|
// Ship skill upgrade
|
|
|
|
ship_upgrade_points: Phaser.Text;
|
|
|
|
ship_upgrades: Phaser.Group;
|
2017-02-27 23:36:12 +00:00
|
|
|
|
2017-02-28 22:34:02 +00:00
|
|
|
// Ship slots
|
|
|
|
ship_slots: Phaser.Group;
|
|
|
|
|
2017-03-05 17:48:13 +00:00
|
|
|
// Ship cargo
|
|
|
|
ship_cargo: Phaser.Group;
|
|
|
|
|
2017-03-23 18:58:09 +00:00
|
|
|
// Mode title
|
|
|
|
mode_title: Phaser.Text;
|
|
|
|
|
2017-03-12 23:32:41 +00:00
|
|
|
// Loot items
|
2017-03-14 17:48:04 +00:00
|
|
|
loot_slots: Phaser.Group;
|
|
|
|
loot_items: Equipment[] = [];
|
2017-03-12 23:32:41 +00:00
|
|
|
|
2017-03-23 18:58:09 +00:00
|
|
|
// Shop
|
|
|
|
shop: Shop | null = null;
|
|
|
|
|
2017-02-27 23:36:12 +00:00
|
|
|
// Fleet's portraits
|
|
|
|
portraits: Phaser.Group;
|
|
|
|
|
2017-03-05 23:29:02 +00:00
|
|
|
// Layer for draggable equipments
|
|
|
|
equipments: Phaser.Group;
|
|
|
|
|
2017-02-27 23:36:12 +00:00
|
|
|
// Credits
|
|
|
|
credits: Phaser.Text;
|
|
|
|
|
|
|
|
// Attributes and skills
|
|
|
|
attributes: { [key: string]: Phaser.Text } = {};
|
|
|
|
|
2017-02-28 00:07:37 +00:00
|
|
|
constructor(view: BaseView, xhidden = -2000, xshown = 0) {
|
2017-02-27 23:36:12 +00:00
|
|
|
super(view.game, 0, 0, "character-sheet");
|
|
|
|
|
2017-03-15 21:40:19 +00:00
|
|
|
this.view = view;
|
|
|
|
|
2017-02-28 00:07:37 +00:00
|
|
|
this.x = xhidden;
|
|
|
|
this.xshown = xshown;
|
|
|
|
this.xhidden = xhidden;
|
2017-02-27 23:36:12 +00:00
|
|
|
this.inputEnabled = true;
|
|
|
|
|
|
|
|
let close_button = new Phaser.Button(this.game, view.getWidth(), 0, "character-close", () => this.hide());
|
|
|
|
close_button.anchor.set(1, 0);
|
|
|
|
this.addChild(close_button);
|
2017-03-15 21:40:19 +00:00
|
|
|
view.tooltip.bindStaticText(close_button, "Close the character sheet");
|
2017-02-27 23:36:12 +00:00
|
|
|
|
|
|
|
this.ship_name = new Phaser.Text(this.game, 758, 48, "", { align: "center", font: "30pt Arial", fill: "#FFFFFF" });
|
|
|
|
this.ship_name.anchor.set(0.5, 0.5);
|
|
|
|
this.addChild(this.ship_name);
|
|
|
|
|
|
|
|
this.ship_level = new Phaser.Text(this.game, 552, 1054, "", { align: "center", font: "30pt Arial", fill: "#FFFFFF" });
|
|
|
|
this.ship_level.anchor.set(0.5, 0.5);
|
|
|
|
this.addChild(this.ship_level);
|
|
|
|
|
2017-03-17 00:07:00 +00:00
|
|
|
this.ship_upgrade_points = new Phaser.Text(this.game, 1066, 1054, "", { align: "center", font: "30pt Arial", fill: "#FFFFFF" });
|
|
|
|
this.ship_upgrade_points.anchor.set(0.5, 0.5);
|
|
|
|
this.addChild(this.ship_upgrade_points);
|
|
|
|
|
|
|
|
this.ship_upgrades = new Phaser.Group(this.game);
|
2017-02-27 23:36:12 +00:00
|
|
|
this.addChild(this.ship_upgrades);
|
|
|
|
|
2017-02-28 22:34:02 +00:00
|
|
|
this.ship_slots = new Phaser.Group(this.game);
|
|
|
|
this.ship_slots.position.set(372, 120);
|
|
|
|
this.addChild(this.ship_slots);
|
|
|
|
|
2017-03-05 17:48:13 +00:00
|
|
|
this.ship_cargo = new Phaser.Group(this.game);
|
|
|
|
this.ship_cargo.position.set(1240, 86);
|
|
|
|
this.addChild(this.ship_cargo);
|
|
|
|
|
2017-03-14 17:48:04 +00:00
|
|
|
this.loot_slots = new Phaser.Group(this.game);
|
|
|
|
this.loot_slots.position.set(1270, 670);
|
|
|
|
this.loot_slots.visible = false;
|
|
|
|
this.addChild(this.loot_slots);
|
2017-03-12 23:32:41 +00:00
|
|
|
|
2017-02-27 23:36:12 +00:00
|
|
|
this.portraits = new Phaser.Group(this.game);
|
|
|
|
this.portraits.position.set(152, 0);
|
|
|
|
this.addChild(this.portraits);
|
|
|
|
|
|
|
|
this.credits = new Phaser.Text(this.game, 136, 38, "", { align: "center", font: "30pt Arial", fill: "#FFFFFF" });
|
|
|
|
this.credits.anchor.set(0.5, 0.5);
|
|
|
|
this.addChild(this.credits);
|
|
|
|
|
2017-03-05 23:29:02 +00:00
|
|
|
this.equipments = new Phaser.Group(this.game);
|
|
|
|
this.addChild(this.equipments);
|
|
|
|
|
2017-03-23 18:58:09 +00:00
|
|
|
this.mode_title = new Phaser.Text(this.game, 1548, 648, "", { align: "center", font: "18pt Arial", fill: "#FFFFFF" });
|
|
|
|
this.mode_title.anchor.set(0.5, 0.5);
|
|
|
|
this.addChild(this.mode_title);
|
|
|
|
|
2017-02-27 23:36:12 +00:00
|
|
|
let x1 = 664;
|
|
|
|
let x2 = 1066;
|
|
|
|
let y = 662;
|
2017-03-17 00:07:00 +00:00
|
|
|
this.addAttribute("initiative", x1, y);
|
|
|
|
this.addAttribute("hull_capacity", x1, y + 64);
|
|
|
|
this.addAttribute("shield_capacity", x1, y + 128);
|
|
|
|
this.addAttribute("power_capacity", x1, y + 192);
|
|
|
|
this.addAttribute("power_initial", x1, y + 256);
|
|
|
|
this.addAttribute("power_recovery", x1, y + 320);
|
|
|
|
this.addAttribute("skill_material", x2, y);
|
|
|
|
this.addAttribute("skill_electronics", x2, y + 64);
|
|
|
|
this.addAttribute("skill_energy", x2, y + 128);
|
|
|
|
this.addAttribute("skill_human", x2, y + 192);
|
|
|
|
this.addAttribute("skill_gravity", x2, y + 256);
|
|
|
|
this.addAttribute("skill_time", x2, y + 320);
|
2017-02-27 23:36:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add an attribute display
|
|
|
|
*/
|
2017-03-17 00:07:00 +00:00
|
|
|
private addAttribute(attribute: keyof ShipAttributes, x: number, y: number) {
|
2017-02-27 23:36:12 +00:00
|
|
|
let text = new Phaser.Text(this.game, x, y, "", { align: "center", font: "18pt Arial", fill: "#FFFFFF" });
|
|
|
|
text.anchor.set(0.5, 0.5);
|
|
|
|
this.addChild(text);
|
|
|
|
|
2017-03-17 00:07:00 +00:00
|
|
|
this.attributes[SHIP_ATTRIBUTES[attribute].name] = text;
|
|
|
|
|
|
|
|
if (SHIP_SKILLS[attribute]) {
|
|
|
|
let button = new Phaser.Button(this.game, x + 54, y - 4, "character-skill-upgrade", () => {
|
|
|
|
this.ship.upgradeSkill(<keyof ShipSkills>attribute);
|
|
|
|
this.refresh();
|
|
|
|
});
|
|
|
|
button.anchor.set(0.5, 0.5);
|
|
|
|
this.ship_upgrades.add(button);
|
|
|
|
|
|
|
|
this.view.tooltip.bindStaticText(button, `Spend one point to upgrade ${SHIP_ATTRIBUTES[attribute].name}`);
|
|
|
|
}
|
2017-02-27 23:36:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Update the fleet sidebar
|
|
|
|
*/
|
|
|
|
updateFleet(fleet: Fleet) {
|
|
|
|
if (fleet != this.fleet) {
|
|
|
|
this.portraits.removeAll(true);
|
|
|
|
this.fleet = fleet;
|
|
|
|
}
|
|
|
|
|
|
|
|
fleet.ships.forEach((ship, idx) => {
|
2017-03-22 21:16:59 +00:00
|
|
|
let portrait = this.portraits.children.length > idx ? <CharacterFleetMember>this.portraits.getChildAt(idx) : null;
|
|
|
|
if (!portrait) {
|
|
|
|
portrait = new CharacterFleetMember(this, 0, idx * 320, ship);
|
|
|
|
this.portraits.add(portrait);
|
2017-02-27 23:36:12 +00:00
|
|
|
}
|
2017-03-22 21:16:59 +00:00
|
|
|
portrait.setSelected(ship == this.ship);
|
2017-02-27 23:36:12 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
this.credits.setText(fleet.credits.toString());
|
|
|
|
|
|
|
|
this.portraits.scale.set(980 * this.portraits.scale.x / this.portraits.height, 980 * this.portraits.scale.y / this.portraits.height);
|
|
|
|
this.portraits.y = 80 + 160 * this.portraits.scale.x;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Show the sheet for a given ship
|
|
|
|
*/
|
|
|
|
show(ship: Ship, animate = true) {
|
|
|
|
this.ship = ship;
|
|
|
|
|
2017-03-05 23:29:02 +00:00
|
|
|
this.equipments.removeAll(true);
|
|
|
|
|
2017-03-17 00:07:00 +00:00
|
|
|
let upgrade_points = ship.getAvailableUpgradePoints();
|
|
|
|
|
2017-02-27 23:36:12 +00:00
|
|
|
this.ship_name.setText(ship.name);
|
2017-03-17 00:07:00 +00:00
|
|
|
this.ship_level.setText(ship.level.get().toString());
|
|
|
|
this.ship_upgrade_points.setText(upgrade_points.toString());
|
|
|
|
this.ship_upgrades.visible = upgrade_points > 0;
|
2017-02-27 23:36:12 +00:00
|
|
|
|
|
|
|
iteritems(<any>ship.attributes, (key, value: ShipAttribute) => {
|
|
|
|
let text = this.attributes[value.name];
|
|
|
|
if (text) {
|
|
|
|
text.setText(value.get().toString());
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2017-02-28 22:34:02 +00:00
|
|
|
let slotsinfo = CharacterSheet.getSlotPositions(ship.slots.length, 800, 454, 200, 200);
|
|
|
|
this.ship_slots.removeAll(true);
|
|
|
|
ship.slots.forEach((slot, idx) => {
|
|
|
|
let slot_display = new CharacterSlot(this, slotsinfo.positions[idx].x, slotsinfo.positions[idx].y, slot.type);
|
|
|
|
slot_display.scale.set(slotsinfo.scaling, slotsinfo.scaling);
|
|
|
|
this.ship_slots.addChild(slot_display);
|
2017-03-05 17:48:13 +00:00
|
|
|
|
|
|
|
if (slot.attached) {
|
2017-03-22 21:16:59 +00:00
|
|
|
let equipment = new CharacterEquipment(this, slot.attached, slot_display);
|
2017-03-05 23:29:02 +00:00
|
|
|
this.equipments.addChild(equipment);
|
2017-03-05 17:48:13 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
slotsinfo = CharacterSheet.getSlotPositions(ship.cargo_space, 638, 496, 200, 200);
|
|
|
|
this.ship_cargo.removeAll(true);
|
|
|
|
range(ship.cargo_space).forEach(idx => {
|
|
|
|
let cargo_slot = new CharacterCargo(this, slotsinfo.positions[idx].x, slotsinfo.positions[idx].y);
|
|
|
|
cargo_slot.scale.set(slotsinfo.scaling, slotsinfo.scaling);
|
|
|
|
this.ship_cargo.addChild(cargo_slot);
|
2017-03-05 23:29:02 +00:00
|
|
|
|
|
|
|
if (idx < this.ship.cargo.length) {
|
2017-03-22 21:16:59 +00:00
|
|
|
let equipment = new CharacterEquipment(this, this.ship.cargo[idx], cargo_slot);
|
2017-03-05 23:29:02 +00:00
|
|
|
this.equipments.addChild(equipment);
|
|
|
|
}
|
2017-02-28 22:34:02 +00:00
|
|
|
});
|
|
|
|
|
2017-03-14 17:48:04 +00:00
|
|
|
this.updateLoot();
|
|
|
|
|
2017-02-27 23:36:12 +00:00
|
|
|
this.updateFleet(ship.fleet);
|
|
|
|
|
2017-03-23 18:58:09 +00:00
|
|
|
if (this.shop) {
|
|
|
|
this.updatePrices(this.shop);
|
|
|
|
}
|
|
|
|
|
2017-02-27 23:36:12 +00:00
|
|
|
if (animate) {
|
2017-02-28 00:07:37 +00:00
|
|
|
this.game.tweens.create(this).to({ x: this.xshown }, 800, Phaser.Easing.Circular.InOut, true);
|
2017-02-27 23:36:12 +00:00
|
|
|
} else {
|
2017-02-28 00:07:37 +00:00
|
|
|
this.x = this.xshown;
|
2017-02-27 23:36:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Hide the sheet
|
|
|
|
*/
|
2017-02-28 00:07:37 +00:00
|
|
|
hide(animate = true) {
|
2017-03-23 18:58:09 +00:00
|
|
|
this.loot_items = [];
|
|
|
|
this.shop = null;
|
2017-03-14 17:48:04 +00:00
|
|
|
this.loot_slots.visible = false;
|
2017-03-23 18:58:09 +00:00
|
|
|
this.mode_title.visible = false;
|
2017-03-14 17:48:04 +00:00
|
|
|
|
2017-02-28 00:07:37 +00:00
|
|
|
this.portraits.children.forEach((portrait: Phaser.Button) => portrait.loadTexture("character-ship"));
|
|
|
|
|
|
|
|
if (animate) {
|
|
|
|
this.game.tweens.create(this).to({ x: this.xhidden }, 800, Phaser.Easing.Circular.InOut, true);
|
|
|
|
} else {
|
|
|
|
this.x = this.xhidden;
|
|
|
|
}
|
2017-02-28 22:34:02 +00:00
|
|
|
}
|
|
|
|
|
2017-03-12 23:32:41 +00:00
|
|
|
/**
|
2017-03-14 17:48:04 +00:00
|
|
|
* Set the list of lootable equipment
|
2017-03-12 23:32:41 +00:00
|
|
|
*
|
|
|
|
* The list of equipments may be altered if items are taken from it
|
2017-03-23 18:58:09 +00:00
|
|
|
*
|
|
|
|
* This list will be shown until sheet is closed
|
2017-03-12 23:32:41 +00:00
|
|
|
*/
|
|
|
|
setLoot(loot: Equipment[]) {
|
2017-03-14 17:48:04 +00:00
|
|
|
this.loot_items = loot;
|
|
|
|
this.updateLoot();
|
|
|
|
this.loot_slots.visible = true;
|
2017-03-23 18:58:09 +00:00
|
|
|
|
|
|
|
this.mode_title.setText("Lootable items");
|
|
|
|
this.mode_title.visible = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the displayed shop
|
|
|
|
*
|
|
|
|
* This shop will be shown until sheet is closed
|
|
|
|
*/
|
|
|
|
setShop(shop: Shop) {
|
|
|
|
this.shop = shop;
|
|
|
|
this.updateLoot();
|
|
|
|
this.loot_slots.visible = true;
|
|
|
|
|
|
|
|
this.mode_title.setText("Shop's equipment");
|
|
|
|
this.mode_title.visible = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Update the price tags on each equipment, for a specific shop
|
|
|
|
*/
|
|
|
|
updatePrices(shop: Shop) {
|
|
|
|
this.equipments.children.forEach((equipement: CharacterEquipment) => {
|
|
|
|
equipement.setPrice(shop.getPrice(equipement.item));
|
|
|
|
});
|
2017-03-14 17:48:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Update the loot slots
|
|
|
|
*/
|
|
|
|
private updateLoot() {
|
|
|
|
this.loot_slots.removeAll(true);
|
2017-03-12 23:32:41 +00:00
|
|
|
|
2017-03-14 17:48:04 +00:00
|
|
|
let info = CharacterSheet.getSlotPositions(12, 588, 354, 196, 196);
|
2017-03-12 23:32:41 +00:00
|
|
|
range(12).forEach(idx => {
|
2017-03-23 18:58:09 +00:00
|
|
|
let loot_slot = this.shop ? new CharacterShopSlot(this, info.positions[idx].x, info.positions[idx].y) : new CharacterLootSlot(this, info.positions[idx].x, info.positions[idx].y);
|
2017-03-12 23:32:41 +00:00
|
|
|
loot_slot.scale.set(info.scaling, info.scaling);
|
2017-03-14 17:48:04 +00:00
|
|
|
this.loot_slots.addChild(loot_slot);
|
2017-03-12 23:32:41 +00:00
|
|
|
|
2017-03-14 17:48:04 +00:00
|
|
|
if (idx < this.loot_items.length) {
|
2017-03-22 21:16:59 +00:00
|
|
|
let equipment = new CharacterEquipment(this, this.loot_items[idx], loot_slot);
|
2017-03-12 23:32:41 +00:00
|
|
|
this.equipments.addChild(equipment);
|
2017-03-23 18:58:09 +00:00
|
|
|
} else if (this.shop && idx < this.shop.stock.length) {
|
|
|
|
let equipment = new CharacterEquipment(this, this.shop.stock[idx], loot_slot);
|
|
|
|
this.equipments.addChild(equipment);
|
2017-03-12 23:32:41 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-03-05 23:29:02 +00:00
|
|
|
/**
|
2017-03-22 21:16:59 +00:00
|
|
|
* Get an iterator over equipment containers
|
2017-03-05 23:29:02 +00:00
|
|
|
*/
|
2017-03-22 21:16:59 +00:00
|
|
|
iEquipmentContainers(): Iterator<CharacterEquipmentContainer> {
|
|
|
|
let candidates = ichain<CharacterEquipmentContainer>(
|
|
|
|
iarray(<CharacterFleetMember[]>this.portraits.children),
|
2017-03-05 23:29:02 +00:00
|
|
|
iarray(<CharacterSlot[]>this.ship_slots.children),
|
2017-03-14 17:48:04 +00:00
|
|
|
iarray(<CharacterCargo[]>this.ship_cargo.children),
|
2017-03-05 23:29:02 +00:00
|
|
|
);
|
|
|
|
|
2017-03-22 21:16:59 +00:00
|
|
|
if (this.loot_slots.visible) {
|
|
|
|
candidates = ichain(candidates, iarray(<CharacterLootSlot[]>this.loot_slots.children));
|
|
|
|
}
|
|
|
|
|
|
|
|
return candidates;
|
2017-03-05 23:29:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Refresh the sheet display
|
|
|
|
*/
|
|
|
|
refresh() {
|
|
|
|
this.show(this.ship);
|
|
|
|
}
|
|
|
|
|
2017-02-28 22:34:02 +00:00
|
|
|
/**
|
2017-03-05 17:48:13 +00:00
|
|
|
* Get the positions and scaling for slots, to fit in a rectangle group.
|
2017-02-28 22:34:02 +00:00
|
|
|
*/
|
|
|
|
static getSlotPositions(count: number, areawidth: number, areaheight: number, slotwidth: number, slotheight: number): { positions: { x: number, y: number }[], scaling: number } {
|
|
|
|
// Find grid size
|
|
|
|
let rows = 2;
|
|
|
|
let columns = 3;
|
|
|
|
while (count > rows * columns) {
|
|
|
|
rows += 1;
|
|
|
|
columns += 1;
|
|
|
|
}
|
2017-02-28 00:07:37 +00:00
|
|
|
|
2017-02-28 22:34:02 +00:00
|
|
|
// Find scaling
|
|
|
|
let scaling = 1;
|
2017-03-14 17:48:04 +00:00
|
|
|
while (slotwidth * scaling * columns > areawidth || slotheight * scaling * rows > areaheight) {
|
2017-02-28 22:34:02 +00:00
|
|
|
scaling *= 0.99;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Position
|
|
|
|
let positions = range(count).map(i => {
|
|
|
|
let row = Math.floor(i / columns);
|
|
|
|
let column = i % columns;
|
|
|
|
return { x: column * (areawidth - slotwidth * scaling) / (columns - 1), y: row * (areaheight - slotheight * scaling) / (rows - 1) };
|
|
|
|
});
|
|
|
|
return { positions: positions, scaling: scaling };
|
2017-02-27 23:36:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|