174 lines
6.4 KiB
TypeScript
174 lines
6.4 KiB
TypeScript
module TS.SpaceTac.UI {
|
|
/**
|
|
* Interface for any graphical area that may contain or receive an equipment
|
|
*/
|
|
export interface CharacterEquipmentContainer {
|
|
/**
|
|
* Check if a point in the character sheet is inside the container
|
|
*/
|
|
isInside(x: number, y: number): boolean
|
|
/**
|
|
* Get a centric anchor point and scaling to snap the equipment
|
|
*/
|
|
getEquipmentAnchor(): { x: number, y: number, scale: number, alpha: number }
|
|
/**
|
|
* Get a vertical offset to position the price tag
|
|
*/
|
|
getPriceOffset(): number
|
|
/**
|
|
* Add an equipment to the container
|
|
*/
|
|
addEquipment(equipment: CharacterEquipment, source: CharacterEquipmentContainer | null, test: boolean): boolean
|
|
/**
|
|
* Remove an equipment from the container
|
|
*/
|
|
removeEquipment(equipment: CharacterEquipment, destination: CharacterEquipmentContainer | null, test: boolean): boolean
|
|
}
|
|
|
|
/**
|
|
* Display a ship equipment, either attached to a slot, in cargo, or being dragged down
|
|
*/
|
|
export class CharacterEquipment extends Phaser.Button {
|
|
sheet: CharacterSheet
|
|
item: Equipment
|
|
container: CharacterEquipmentContainer
|
|
price: number
|
|
|
|
constructor(sheet: CharacterSheet, equipment: Equipment, container: CharacterEquipmentContainer) {
|
|
let icon = sheet.view.getImageInfo(`equipment-${equipment.code}`);
|
|
super(sheet.game, 0, 0, icon.key, undefined, undefined, icon.frame, icon.frame);
|
|
|
|
this.sheet = sheet;
|
|
this.item = equipment;
|
|
this.container = container;
|
|
this.price = 0;
|
|
|
|
this.anchor.set(0.5, 0.5);
|
|
|
|
this.setupDragDrop(sheet);
|
|
this.snapToContainer();
|
|
|
|
sheet.view.tooltip.bind(this, filler => this.fillTooltip(filler));
|
|
}
|
|
|
|
jasmineToString() {
|
|
return this.item.jasmineToString();
|
|
}
|
|
|
|
/**
|
|
* Find the container under a specific screen location
|
|
*/
|
|
findContainerAt(x: number, y: number): CharacterEquipmentContainer | null {
|
|
return ifirst(this.sheet.iEquipmentContainers(), container => container.isInside(x, y));
|
|
}
|
|
|
|
/**
|
|
* Display a price tag
|
|
*/
|
|
setPrice(price: number) {
|
|
if (!price || this.price) {
|
|
return;
|
|
}
|
|
this.price = price;
|
|
|
|
let tag = new Phaser.Image(this.game, 0, 0, "character-price-tag");
|
|
let yoffset = this.container.getPriceOffset();
|
|
tag.position.set(0, -yoffset * 2 + tag.height);
|
|
tag.anchor.set(0.5, 0.5);
|
|
tag.scale.set(2, 2);
|
|
tag.alpha = 0.85;
|
|
this.addChild(tag);
|
|
|
|
let text = new Phaser.Text(this.game, -10, 4, price.toString(), { align: "center", font: "18pt Arial", fill: "#FFFFCC" });
|
|
text.anchor.set(0.5, 0.5);
|
|
tag.addChild(text);
|
|
}
|
|
|
|
/**
|
|
* Snap in place to its current container
|
|
*/
|
|
snapToContainer() {
|
|
let info = this.container.getEquipmentAnchor();
|
|
this.position.set(info.x, info.y);
|
|
this.scale.set(0.5 * info.scale, 0.5 * info.scale);
|
|
this.alpha = info.alpha;
|
|
}
|
|
|
|
/**
|
|
* Enable dragging to another slot
|
|
*/
|
|
setupDragDrop(sheet: CharacterSheet) {
|
|
this.inputEnabled = true;
|
|
if (this.container.removeEquipment(this, null, true)) {
|
|
this.input.enableDrag(false, true);
|
|
}
|
|
|
|
this.events.onDragStart.add(() => {
|
|
this.sheet.view.audio.playOnce("ui-drag");
|
|
this.scale.set(0.5, 0.5);
|
|
this.alpha = 0.8;
|
|
});
|
|
this.events.onDragStop.add(() => {
|
|
this.sheet.view.audio.playOnce("ui-drop");
|
|
let destination = this.findContainerAt(this.x, this.y);
|
|
if (destination && destination != this.container) {
|
|
if (this.applyDragDrop(this.container, destination, false)) {
|
|
this.container = destination;
|
|
this.snapToContainer();
|
|
sheet.refresh(); // TODO Only if required (destination is "virtual")
|
|
} else {
|
|
this.snapToContainer();
|
|
}
|
|
} else {
|
|
this.snapToContainer();
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Apply drag and drop between two containers
|
|
*
|
|
* Return true if something changed (or would change, if test=true).
|
|
*/
|
|
applyDragDrop(source: CharacterEquipmentContainer, destination: CharacterEquipmentContainer, test: boolean): boolean {
|
|
let possible = source.removeEquipment(this, destination, true) && destination.addEquipment(this, source, true);
|
|
if (test) {
|
|
return possible;
|
|
} else if (possible) {
|
|
if (source.removeEquipment(this, destination, false)) {
|
|
if (destination.addEquipment(this, source, false)) {
|
|
return true;
|
|
} else {
|
|
console.error("Destination container refused to accept equipment", this, source, destination);
|
|
// Go back to source
|
|
if (source.addEquipment(this, null, false)) {
|
|
return false;
|
|
} else {
|
|
console.error("Equipment lost in bad exchange !", this, source, destination);
|
|
return true;
|
|
}
|
|
}
|
|
} else {
|
|
console.error("Source container refused to give away equipment", this, source, destination);
|
|
return false;
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fill a tooltip with equipment data
|
|
*/
|
|
fillTooltip(filler: TooltipFiller): boolean {
|
|
let title = this.item.getFullName();
|
|
if (this.item.slot_type !== null) {
|
|
title += ` (${SlotType[this.item.slot_type]})`;
|
|
}
|
|
filler.addText(0, 0, title, "#cccccc", 20, false, true);
|
|
filler.addText(0, 40, this.item.getFullDescription(), "#cccccc", 18, false, false, 700);
|
|
return true;
|
|
}
|
|
}
|
|
}
|