character sheet: Added ability to transfer items between ships
This commit is contained in:
parent
9c358113db
commit
7f9f13d781
1
TODO
1
TODO
|
@ -1,5 +1,4 @@
|
|||
* UI: Use a common component class, and a layer abstraction
|
||||
* Character sheet: allow item moving to another ship
|
||||
* Character sheet: add tooltips (on values, slots and equipments)
|
||||
* Character sheet: add initial character creation
|
||||
* Character sheet: disable interaction during battle (except for loot screen)
|
||||
|
|
|
@ -41,7 +41,7 @@ module TS.SpaceTac {
|
|||
target_effects: BaseEffect[];
|
||||
|
||||
// Basic constructor
|
||||
constructor(slot: SlotType | null = null, code = "equiment") {
|
||||
constructor(slot: SlotType | null = null, code = "equipment") {
|
||||
this.slot = slot;
|
||||
this.code = code;
|
||||
this.name = code;
|
||||
|
|
|
@ -37,7 +37,7 @@ module TS.SpaceTac.Specs {
|
|||
expect(result.total_fire_ap).toBe(3, 'total_fire_ap');
|
||||
|
||||
expect(result.parts).toEqual([
|
||||
{ action: jasmine.objectContaining({ code: "fire-equiment" }), target: new Target(ship.arena_x + 5, ship.arena_y, null), ap: 3, possible: true }
|
||||
{ action: jasmine.objectContaining({ code: "fire-equipment" }), target: new Target(ship.arena_x + 5, ship.arena_y, null), ap: 3, possible: true }
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -51,7 +51,7 @@ module TS.SpaceTac.Specs {
|
|||
expect(result.total_fire_ap).toBe(3, 'total_fire_ap');
|
||||
|
||||
expect(result.parts).toEqual([
|
||||
{ action: jasmine.objectContaining({ code: "fire-equiment" }), target: new Target(ship.arena_x + 5, ship.arena_y, null), ap: 3, possible: false }
|
||||
{ action: jasmine.objectContaining({ code: "fire-equipment" }), target: new Target(ship.arena_x + 5, ship.arena_y, null), ap: 3, possible: false }
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -69,7 +69,7 @@ module TS.SpaceTac.Specs {
|
|||
|
||||
expect(result.parts).toEqual([
|
||||
{ action: jasmine.objectContaining({ code: "move" }), target: new Target(ship.arena_x + 5, ship.arena_y, null), ap: 1, possible: true },
|
||||
{ action: jasmine.objectContaining({ code: "fire-equiment" }), target: new Target(ship.arena_x + 15, ship.arena_y, null), ap: 3, possible: true }
|
||||
{ action: jasmine.objectContaining({ code: "fire-equipment" }), target: new Target(ship.arena_x + 15, ship.arena_y, null), ap: 3, possible: true }
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -87,7 +87,7 @@ module TS.SpaceTac.Specs {
|
|||
|
||||
expect(result.parts).toEqual([
|
||||
{ action: jasmine.objectContaining({ code: "move" }), target: new Target(ship.arena_x + 10, ship.arena_y, null), ap: 2, possible: true },
|
||||
{ action: jasmine.objectContaining({ code: "fire-equiment" }), target: new Target(ship.arena_x + 18, ship.arena_y, null), ap: 2, possible: false }
|
||||
{ action: jasmine.objectContaining({ code: "fire-equipment" }), target: new Target(ship.arena_x + 18, ship.arena_y, null), ap: 2, possible: false }
|
||||
]);
|
||||
});
|
||||
|
||||
|
|
|
@ -322,12 +322,15 @@ module TS.SpaceTac.Specs {
|
|||
let result = ship.addCargo(equipment1);
|
||||
expect(result).toBe(false);
|
||||
expect(ship.cargo).toEqual([]);
|
||||
expect(ship.getFreeCargoSpace()).toBe(0);
|
||||
|
||||
ship.setCargoSpace(1);
|
||||
expect(ship.getFreeCargoSpace()).toBe(1);
|
||||
|
||||
result = ship.addCargo(equipment1);
|
||||
expect(result).toBe(true);
|
||||
expect(ship.cargo).toEqual([equipment1]);
|
||||
expect(ship.getFreeCargoSpace()).toBe(0);
|
||||
|
||||
result = ship.addCargo(equipment1);
|
||||
expect(result).toBe(false);
|
||||
|
@ -338,18 +341,20 @@ module TS.SpaceTac.Specs {
|
|||
expect(ship.cargo).toEqual([equipment1]);
|
||||
|
||||
ship.setCargoSpace(2);
|
||||
expect(ship.getFreeCargoSpace()).toBe(1);
|
||||
|
||||
result = ship.addCargo(equipment2);
|
||||
expect(result).toBe(true);
|
||||
expect(ship.cargo).toEqual([equipment1, equipment2]);
|
||||
expect(ship.getFreeCargoSpace()).toBe(0);
|
||||
|
||||
ship.setCargoSpace(1);
|
||||
|
||||
expect(ship.cargo).toEqual([equipment1]);
|
||||
expect(ship.getFreeCargoSpace()).toBe(0);
|
||||
|
||||
ship.setCargoSpace(2);
|
||||
|
||||
expect(ship.cargo).toEqual([equipment1]);
|
||||
expect(ship.getFreeCargoSpace()).toBe(1);
|
||||
});
|
||||
|
||||
it("equips items from cargo", function () {
|
||||
|
|
|
@ -453,6 +453,13 @@ module TS.SpaceTac {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cargo space not occupied by items
|
||||
*/
|
||||
getFreeCargoSpace(): number {
|
||||
return this.cargo_space - this.cargo.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the available cargo space.
|
||||
*/
|
||||
|
@ -488,11 +495,10 @@ module TS.SpaceTac {
|
|||
*
|
||||
* Returns true if successful
|
||||
*/
|
||||
equip(item: Equipment): boolean {
|
||||
equip(item: Equipment, from_cargo = true): boolean {
|
||||
let free_slot = first(this.slots, slot => slot.type == item.slot && !slot.attached);
|
||||
|
||||
if (free_slot && contains(this.cargo, item)) {
|
||||
remove(this.cargo, item);
|
||||
if (free_slot && (!from_cargo || remove(this.cargo, item))) {
|
||||
free_slot.attach(item);
|
||||
|
||||
this.updateAttributes();
|
||||
|
@ -508,10 +514,12 @@ module TS.SpaceTac {
|
|||
*
|
||||
* Returns true if successful
|
||||
*/
|
||||
unequip(item: Equipment): boolean {
|
||||
if (item.attached_to && item.attached_to.attached == item && this.cargo.length < this.cargo_space) {
|
||||
unequip(item: Equipment, to_cargo = true): boolean {
|
||||
if (item.attached_to && item.attached_to.attached == item && (!to_cargo || this.cargo.length < this.cargo_space)) {
|
||||
item.detach();
|
||||
add(this.cargo, item);
|
||||
if (to_cargo) {
|
||||
add(this.cargo, item);
|
||||
}
|
||||
|
||||
this.updateAttributes();
|
||||
|
||||
|
@ -537,6 +545,13 @@ module TS.SpaceTac {
|
|||
return nna(this.slots.filter(slot => slot.attached && (slottype == null || slot.type == slottype)).map(slot => slot.attached));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first free slot of a given type, null if none is available
|
||||
*/
|
||||
getFreeSlot(type: SlotType): Slot | null {
|
||||
return first(this.slots, slot => slot.type == type && slot.attached == null);
|
||||
}
|
||||
|
||||
// Get the number of attached equipments
|
||||
getEquipmentCount(): number {
|
||||
var result = 0;
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
/// <reference path="CharacterEquipment.ts" />
|
||||
|
||||
module TS.SpaceTac.UI {
|
||||
/**
|
||||
* Display a ship cargo slot
|
||||
*/
|
||||
export class CharacterCargo extends Phaser.Image {
|
||||
export class CharacterCargo extends Phaser.Image implements CharacterEquipmentContainer {
|
||||
sheet: CharacterSheet;
|
||||
|
||||
constructor(sheet: CharacterSheet, x: number, y: number) {
|
||||
|
@ -12,35 +14,38 @@ module TS.SpaceTac.UI {
|
|||
}
|
||||
|
||||
/**
|
||||
* Snap the equipment icon inside the slot
|
||||
* CharacterEquipmentContainer interface
|
||||
*/
|
||||
snapEquipment(equipment: CharacterEquipment) {
|
||||
equipment.position.set(this.x + this.parent.x + 98 * this.scale.x, this.y + this.parent.y + 98 * this.scale.y);
|
||||
equipment.setContainerScale(this.scale.x);
|
||||
isInside(x: number, y: number): boolean {
|
||||
return this.getBounds().contains(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an equipment can be dropped in this slot
|
||||
*/
|
||||
canDropEquipment(equipment: Equipment, x: number, y: number): CharacterEquipmentDrop | null {
|
||||
if (this.getBounds().contains(x, y)) {
|
||||
if (contains(this.sheet.loot_items, equipment)) {
|
||||
return {
|
||||
message: "Loot",
|
||||
callback: () => {
|
||||
if (this.sheet.ship.addCargo(equipment)) {
|
||||
remove(this.sheet.loot_items, equipment);
|
||||
}
|
||||
}
|
||||
};
|
||||
getEquipmentAnchor(): { x: number, y: number, scale: number } {
|
||||
return {
|
||||
x: this.x + this.parent.x + 98 * this.scale.x,
|
||||
y: this.y + this.parent.y + 98 * this.scale.y,
|
||||
scale: this.scale.x
|
||||
}
|
||||
}
|
||||
addEquipment(equipment: CharacterEquipment, source: CharacterEquipmentContainer | null, test: boolean): boolean {
|
||||
if (this.sheet.ship.getFreeCargoSpace() > 0) {
|
||||
if (test) {
|
||||
return true;
|
||||
} else {
|
||||
return {
|
||||
message: "Unequip",
|
||||
callback: () => this.sheet.ship.unequip(equipment)
|
||||
};
|
||||
return this.sheet.ship.addCargo(equipment.item);
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
removeEquipment(equipment: CharacterEquipment, destination: CharacterEquipmentContainer | null, test: boolean): boolean {
|
||||
if (contains(this.sheet.ship.cargo, equipment.item)) {
|
||||
if (test) {
|
||||
return true;
|
||||
} else {
|
||||
return this.sheet.ship.removeCargo(equipment.item);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,30 +1,70 @@
|
|||
module TS.SpaceTac.UI {
|
||||
/**
|
||||
* Interface for any graphical item that may receive an equipment as drop destination
|
||||
* Interface for any graphical area that may contain or receive an equipment
|
||||
*/
|
||||
export interface CharacterEquipmentDestination {
|
||||
canDropEquipment(equipment: Equipment, x: number, y: number): CharacterEquipmentDrop | null;
|
||||
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 }
|
||||
/**
|
||||
* 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 {
|
||||
equipment: Equipment;
|
||||
sheet: CharacterSheet
|
||||
item: Equipment
|
||||
container: CharacterEquipmentContainer
|
||||
tooltip: string
|
||||
|
||||
constructor(sheet: CharacterSheet, equipment: Equipment) {
|
||||
constructor(sheet: CharacterSheet, equipment: Equipment, container: CharacterEquipmentContainer) {
|
||||
let icon = sheet.game.cache.checkImageKey(`equipment-${equipment.code}`) ? `equipment-${equipment.code}` : `battle-actions-${equipment.action.code}`;
|
||||
super(sheet.game, 0, 0, icon);
|
||||
|
||||
this.equipment = equipment;
|
||||
this.sheet = sheet;
|
||||
this.item = equipment;
|
||||
this.container = container;
|
||||
this.tooltip = equipment.name;
|
||||
|
||||
this.container.addEquipment(this, null, false);
|
||||
|
||||
this.anchor.set(0.5, 0.5);
|
||||
this.scale.set(0.5, 0.5);
|
||||
|
||||
this.setupDragDrop(sheet);
|
||||
this.snapToContainer();
|
||||
|
||||
// TODO better tooltip
|
||||
sheet.view.tooltip.bindStaticText(this, equipment.name);
|
||||
// TODO better tooltip (with equipment characteristics)
|
||||
sheet.view.tooltip.bindDynamicText(this, () => this.tooltip);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = 1.0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -34,36 +74,46 @@ module TS.SpaceTac.UI {
|
|||
this.inputEnabled = true;
|
||||
this.input.enableDrag(false, true);
|
||||
|
||||
let origin: [number, number, number, number] | null = null;
|
||||
let drop: CharacterEquipmentDrop | null = null;
|
||||
this.events.onDragStart.add(() => {
|
||||
origin = [this.x, this.y, this.scale.x, this.scale.y];
|
||||
this.scale.set(0.5, 0.5);
|
||||
this.alpha = 0.8;
|
||||
});
|
||||
this.events.onDragUpdate.add(() => {
|
||||
drop = sheet.canDropEquipment(this.equipment, this.x, this.y);
|
||||
let destination = this.findContainerAt(this.x, this.y);
|
||||
if (destination) {
|
||||
this.applyDragDrop(this.container, destination, true);
|
||||
}
|
||||
});
|
||||
this.events.onDragStop.add(() => {
|
||||
if (drop) {
|
||||
drop.callback(this.equipment);
|
||||
let destination = this.findContainerAt(this.x, this.y);
|
||||
if (destination) {
|
||||
this.applyDragDrop(this.container, destination, false);
|
||||
sheet.refresh();
|
||||
} else {
|
||||
if (origin) {
|
||||
this.position.set(origin[0], origin[1]);
|
||||
this.scale.set(origin[2], origin[3]);
|
||||
origin = null;
|
||||
}
|
||||
this.alpha = 1;
|
||||
this.snapToContainer();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the scaling of container in which the equipment icon is snapped
|
||||
* Apply drag and drop between two containers
|
||||
*/
|
||||
setContainerScale(scale: number) {
|
||||
this.scale.set(0.5 * scale, 0.5 * scale);
|
||||
applyDragDrop(source: CharacterEquipmentContainer, destination: CharacterEquipmentContainer, hold: boolean) {
|
||||
if (source.removeEquipment(this, destination, true) && destination.addEquipment(this, source, true)) {
|
||||
if (!hold) {
|
||||
if (source.removeEquipment(this, destination, false)) {
|
||||
if (!destination.addEquipment(this, source, false)) {
|
||||
console.error("Destination container refused to accept equipment", this, source, destination);
|
||||
// Go back to source
|
||||
if (!source.addEquipment(this, null, true)) {
|
||||
console.error("Equipment lost in bad exchange !", this, source, destination);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.error("Source container refused to give away equipment", this, source, destination);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
62
src/ui/character/CharacterFleetMember.spec.ts
Normal file
62
src/ui/character/CharacterFleetMember.spec.ts
Normal file
|
@ -0,0 +1,62 @@
|
|||
module TS.SpaceTac.UI.Specs {
|
||||
describe("CharacterFleetMember", function () {
|
||||
let testgame = setupEmptyView();
|
||||
|
||||
it("transfers equipment to another ship", function () {
|
||||
let view = testgame.baseview;
|
||||
let sheet = new CharacterSheet(view);
|
||||
|
||||
let fleet = new Fleet();
|
||||
let ship1 = fleet.addShip();
|
||||
ship1.setCargoSpace(3);
|
||||
let equ1 = new Equipment(SlotType.Engine, "engine1");
|
||||
ship1.addCargo(equ1);
|
||||
let equ2 = new Equipment(SlotType.Engine, "engine2");
|
||||
ship1.addCargo(equ2);
|
||||
let equ3 = new Equipment(SlotType.Engine, "engine3");
|
||||
ship1.addCargo(equ3);
|
||||
let ship2 = fleet.addShip();
|
||||
let ship2engine = ship2.addSlot(SlotType.Engine);
|
||||
ship2.setCargoSpace(1);
|
||||
|
||||
sheet.show(ship1);
|
||||
expect(sheet.portraits.length).toBe(2);
|
||||
expect(sheet.equipments.length).toBe(3);
|
||||
expect(sheet.ship_cargo.length).toBe(3);
|
||||
|
||||
// First item fits in the free slot
|
||||
let source = <CharacterCargo>sheet.ship_cargo.children[0];
|
||||
let dest = <CharacterFleetMember>sheet.portraits.children[1];
|
||||
let equ = <CharacterEquipment>sheet.equipments.children[0];
|
||||
expect(dest.ship).toBe(ship2);
|
||||
expect(equ.item).toBe(equ1);
|
||||
expect(ship1.cargo).toContain(equ1);
|
||||
expect(ship2engine.attached).toBe(null);
|
||||
equ.applyDragDrop(source, dest, false);
|
||||
expect(ship1.cargo).not.toContain(equ1);
|
||||
expect(ship2engine.attached).toBe(equ1);
|
||||
|
||||
// Second item goes to cargo
|
||||
source = <CharacterCargo>sheet.ship_cargo.children[0];
|
||||
dest = <CharacterFleetMember>sheet.portraits.children[1];
|
||||
equ = <CharacterEquipment>sheet.equipments.children[1];
|
||||
expect(dest.ship).toBe(ship2);
|
||||
expect(equ.item).toBe(equ2);
|
||||
expect(ship1.cargo).toContain(equ2);
|
||||
expect(ship2.cargo).not.toContain(equ2);
|
||||
equ.applyDragDrop(source, dest, false);
|
||||
expect(ship1.cargo).not.toContain(equ2);
|
||||
expect(ship2.cargo).toContain(equ2);
|
||||
|
||||
// Third item has no more room
|
||||
source = <CharacterCargo>sheet.ship_cargo.children[0];
|
||||
dest = <CharacterFleetMember>sheet.portraits.children[1];
|
||||
equ = <CharacterEquipment>sheet.equipments.children[2];
|
||||
expect(dest.ship).toBe(ship2);
|
||||
expect(equ.item).toBe(equ3);
|
||||
expect(ship1.cargo).toContain(equ3);
|
||||
equ.applyDragDrop(source, dest, false);
|
||||
expect(ship1.cargo).toContain(equ3);
|
||||
});
|
||||
});
|
||||
}
|
71
src/ui/character/CharacterFleetMember.ts
Normal file
71
src/ui/character/CharacterFleetMember.ts
Normal file
|
@ -0,0 +1,71 @@
|
|||
/// <reference path="CharacterEquipment.ts" />
|
||||
|
||||
module TS.SpaceTac.UI {
|
||||
/**
|
||||
* Display a fleet member in the side of character sheet
|
||||
*/
|
||||
export class CharacterFleetMember extends Phaser.Button implements CharacterEquipmentContainer {
|
||||
sheet: CharacterSheet;
|
||||
ship: Ship;
|
||||
|
||||
constructor(sheet: CharacterSheet, x: number, y: number, ship: Ship) {
|
||||
super(sheet.game, x, y, "character-ship", () => sheet.show(ship));
|
||||
this.anchor.set(0.5, 0.5);
|
||||
|
||||
this.sheet = sheet;
|
||||
this.ship = ship;
|
||||
|
||||
let portrait_pic = new Phaser.Image(this.game, 0, 0, `ship-${ship.model}-portrait`);
|
||||
portrait_pic.anchor.set(0.5, 0.5);
|
||||
this.addChild(portrait_pic);
|
||||
|
||||
sheet.view.tooltip.bindDynamicText(this, () => ship.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the selected state of the ship
|
||||
*/
|
||||
setSelected(selected: boolean) {
|
||||
this.loadTexture(selected ? "character-ship-selected" : "character-ship");
|
||||
}
|
||||
|
||||
/**
|
||||
* CharacterEquipmentContainer interface
|
||||
*/
|
||||
isInside(x: number, y: number): boolean {
|
||||
return this.getBounds().contains(x, y);
|
||||
}
|
||||
getEquipmentAnchor(): { x: number, y: number, scale: number } {
|
||||
// not needed, equipment is never shown snapped in the slot
|
||||
return { x: 0, y: 0, scale: 1 };
|
||||
}
|
||||
addEquipment(equipment: CharacterEquipment, source: CharacterEquipmentContainer | null, test: boolean): boolean {
|
||||
if (this.ship != this.sheet.ship && equipment.item.slot !== null) {
|
||||
let slot = this.ship.getFreeSlot(equipment.item.slot);
|
||||
if (slot) {
|
||||
if (test) {
|
||||
return true;
|
||||
} else {
|
||||
return this.ship.equip(equipment.item, false);
|
||||
}
|
||||
} else {
|
||||
if (this.ship.getFreeCargoSpace() > 0) {
|
||||
if (test) {
|
||||
return true;
|
||||
} else {
|
||||
return this.ship.addCargo(equipment.item);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
removeEquipment(equipment: CharacterEquipment, destination: CharacterEquipmentContainer | null, test: boolean): boolean {
|
||||
// should never happen
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
26
src/ui/character/CharacterLootSlot.ts
Normal file
26
src/ui/character/CharacterLootSlot.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
/// <reference path="CharacterEquipment.ts" />
|
||||
|
||||
module TS.SpaceTac.UI {
|
||||
/**
|
||||
* Display a loot slot
|
||||
*/
|
||||
export class CharacterLootSlot extends CharacterCargo {
|
||||
addEquipment(equipment: CharacterEquipment, source: CharacterEquipmentContainer | null, test: boolean): boolean {
|
||||
if (!test) {
|
||||
add(this.sheet.loot_items, equipment.item);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
removeEquipment(equipment: CharacterEquipment, destination: CharacterEquipmentContainer | null, test: boolean): boolean {
|
||||
if (contains(this.sheet.loot_items, equipment.item)) {
|
||||
if (test) {
|
||||
return true;
|
||||
} else {
|
||||
return remove(this.sheet.loot_items, equipment.item);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -63,14 +63,9 @@ module TS.SpaceTac.UI.Specs {
|
|||
expect(sheet.loot_slots.visible).toBe(true);
|
||||
expect(sheet.equipments.children.length).toBe(4);
|
||||
|
||||
let findsprite = (equ: Equipment) => nn(first(<CharacterEquipment[]>sheet.equipments.children, sp => sp.equipment == equ));
|
||||
let findsprite = (equ: Equipment) => nn(first(<CharacterEquipment[]>sheet.equipments.children, sp => sp.item == equ));
|
||||
let draddrop = (sp: CharacterEquipment, dest: CharacterCargo | CharacterSlot) => {
|
||||
let destbounds = dest.getBounds();
|
||||
/*sp.events.onDragStart.dispatch();
|
||||
sp.position.set(destbounds.x, destbounds.y);
|
||||
sp.events.onDragUpdate.dispatch();
|
||||
sp.events.onDragStop.dispatch();*/
|
||||
nn(dest.canDropEquipment(sp.equipment, destbounds.x, destbounds.y)).callback(sp.equipment);
|
||||
sp.applyDragDrop(sp.container, dest, false);
|
||||
}
|
||||
|
||||
// Unequip
|
||||
|
|
|
@ -156,21 +156,12 @@ module TS.SpaceTac.UI {
|
|||
}
|
||||
|
||||
fleet.ships.forEach((ship, idx) => {
|
||||
let portrait = this.portraits.children.length > idx ? this.portraits.getChildAt(idx) : null;
|
||||
let key = ship == this.ship ? "character-ship-selected" : "character-ship";
|
||||
if (portrait instanceof Phaser.Button) {
|
||||
portrait.loadTexture(key);
|
||||
} else {
|
||||
let new_portrait = new Phaser.Button(this.game, 0, idx * 320, key, () => this.show(ship));
|
||||
new_portrait.anchor.set(0.5, 0.5);
|
||||
this.portraits.addChild(new_portrait);
|
||||
|
||||
let portrait_pic = new Phaser.Image(this.game, 0, 0, `ship-${ship.model}-portrait`);
|
||||
portrait_pic.anchor.set(0.5, 0.5);
|
||||
new_portrait.addChild(portrait_pic);
|
||||
|
||||
this.view.tooltip.bindDynamicText(new_portrait, () => ship.name);
|
||||
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);
|
||||
}
|
||||
portrait.setSelected(ship == this.ship);
|
||||
});
|
||||
|
||||
this.credits.setText(fleet.credits.toString());
|
||||
|
@ -209,9 +200,8 @@ module TS.SpaceTac.UI {
|
|||
this.ship_slots.addChild(slot_display);
|
||||
|
||||
if (slot.attached) {
|
||||
let equipment = new CharacterEquipment(this, slot.attached);
|
||||
let equipment = new CharacterEquipment(this, slot.attached, slot_display);
|
||||
this.equipments.addChild(equipment);
|
||||
slot_display.snapEquipment(equipment);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -223,9 +213,8 @@ module TS.SpaceTac.UI {
|
|||
this.ship_cargo.addChild(cargo_slot);
|
||||
|
||||
if (idx < this.ship.cargo.length) {
|
||||
let equipment = new CharacterEquipment(this, this.ship.cargo[idx]);
|
||||
let equipment = new CharacterEquipment(this, this.ship.cargo[idx], cargo_slot);
|
||||
this.equipments.addChild(equipment);
|
||||
cargo_slot.snapEquipment(equipment);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -274,29 +263,32 @@ module TS.SpaceTac.UI {
|
|||
|
||||
let info = CharacterSheet.getSlotPositions(12, 588, 354, 196, 196);
|
||||
range(12).forEach(idx => {
|
||||
let loot_slot = new LootSlot(this, info.positions[idx].x, info.positions[idx].y);
|
||||
let loot_slot = new CharacterLootSlot(this, info.positions[idx].x, info.positions[idx].y);
|
||||
loot_slot.scale.set(info.scaling, info.scaling);
|
||||
this.loot_slots.addChild(loot_slot);
|
||||
|
||||
if (idx < this.loot_items.length) {
|
||||
let equipment = new CharacterEquipment(this, this.loot_items[idx]);
|
||||
let equipment = new CharacterEquipment(this, this.loot_items[idx], loot_slot);
|
||||
this.equipments.addChild(equipment);
|
||||
loot_slot.snapEquipment(equipment);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an equipment can be dropped somewhere
|
||||
* Get an iterator over equipment containers
|
||||
*/
|
||||
canDropEquipment(equipment: Equipment, x: number, y: number): CharacterEquipmentDrop | null {
|
||||
let candidates: Iterator<CharacterEquipmentDestination> = ichain(
|
||||
iEquipmentContainers(): Iterator<CharacterEquipmentContainer> {
|
||||
let candidates = ichain<CharacterEquipmentContainer>(
|
||||
iarray(<CharacterFleetMember[]>this.portraits.children),
|
||||
iarray(<CharacterSlot[]>this.ship_slots.children),
|
||||
iarray(<CharacterCargo[]>this.ship_cargo.children),
|
||||
this.loot_slots.visible ? iarray(<LootSlot[]>this.loot_slots.children) : IEMPTY
|
||||
);
|
||||
|
||||
return ifirstmap(candidates, candidate => candidate.canDropEquipment(equipment, x, y));
|
||||
if (this.loot_slots.visible) {
|
||||
candidates = ichain(candidates, iarray(<CharacterLootSlot[]>this.loot_slots.children));
|
||||
}
|
||||
|
||||
return candidates;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
/// <reference path="CharacterEquipment.ts" />
|
||||
|
||||
module TS.SpaceTac.UI {
|
||||
/**
|
||||
* Display a ship slot, with equipment attached to it
|
||||
*/
|
||||
export class CharacterSlot extends Phaser.Image {
|
||||
export class CharacterSlot extends Phaser.Image implements CharacterEquipmentContainer {
|
||||
sheet: CharacterSheet;
|
||||
|
||||
constructor(sheet: CharacterSheet, x: number, y: number, slot: SlotType) {
|
||||
|
@ -16,25 +18,40 @@ module TS.SpaceTac.UI {
|
|||
sheet.view.tooltip.bindStaticText(sloticon, `${SlotType[slot]} slot`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Snap the equipment icon inside the slot
|
||||
*/
|
||||
snapEquipment(equipment: CharacterEquipment) {
|
||||
equipment.position.set(this.x + this.parent.x + 84 * this.scale.x, this.y + this.parent.y + 83 * this.scale.y);
|
||||
equipment.setContainerScale(this.scale.x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an equipment can be dropped in this slot
|
||||
* CharacterEquipmentContainer interface
|
||||
*/
|
||||
canDropEquipment(equipment: Equipment, x: number, y: number): CharacterEquipmentDrop | null {
|
||||
if (this.getBounds().contains(x, y)) {
|
||||
return {
|
||||
message: "Equip",
|
||||
callback: () => this.sheet.ship.equip(equipment)
|
||||
};
|
||||
isInside(x: number, y: number): boolean {
|
||||
return this.getBounds().contains(x, y);
|
||||
}
|
||||
getEquipmentAnchor(): { x: number, y: number, scale: number } {
|
||||
return {
|
||||
x: this.x + this.parent.x + 84 * this.scale.x,
|
||||
y: this.y + this.parent.y + 83 * this.scale.y,
|
||||
scale: this.scale.x
|
||||
}
|
||||
}
|
||||
addEquipment(equipment: CharacterEquipment, source: CharacterEquipmentContainer | null, test: boolean): boolean {
|
||||
if (equipment.item.slot !== null && this.sheet.ship.getFreeSlot(equipment.item.slot)) {
|
||||
if (test) {
|
||||
return true;
|
||||
} else {
|
||||
return this.sheet.ship.equip(equipment.item, false);
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
removeEquipment(equipment: CharacterEquipment, destination: CharacterEquipmentContainer | null, test: boolean): boolean {
|
||||
if (contains(this.sheet.ship.listEquipment(equipment.item.slot), equipment.item)) {
|
||||
if (test) {
|
||||
return true;
|
||||
} else {
|
||||
return this.sheet.ship.unequip(equipment.item, false);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
module TS.SpaceTac.UI {
|
||||
/**
|
||||
* Display a loot slot
|
||||
*/
|
||||
export class LootSlot extends CharacterCargo {
|
||||
/**
|
||||
* Check if an equipment can be dropped in this slot
|
||||
*/
|
||||
canDropEquipment(equipment: Equipment, x: number, y: number): CharacterEquipmentDrop | null {
|
||||
if (this.getBounds().contains(x, y) && contains(this.sheet.ship.cargo, equipment)) {
|
||||
return {
|
||||
message: "Discard",
|
||||
callback: () => {
|
||||
if (this.sheet.ship.removeCargo(equipment)) {
|
||||
add(this.sheet.loot_items, equipment);
|
||||
}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue