1
0
Fork 0

character sheet: Added info message when dragging equipment

This commit is contained in:
Michaël Lemaire 2017-10-13 01:16:33 +02:00
parent c548793523
commit 4e498cbdbd
15 changed files with 253 additions and 131 deletions

View file

@ -25,8 +25,7 @@ Character sheet
* Disable interaction during battle (except for loot screen)
* Improve eye-catching for shop and loot section
* Highlight allowed destinations during drag-and-drop, with text hints (for success or error)
* When transferring to another ship, if the item can't be equipped (unmatched requirements), the transfer is cancelled instead of trying cargo
* Highlight allowed destinations during drag-and-drop
* Effective skill is sometimes not updated when upgrading base skill
* Add merged cargo display for the whole fleet
* Allow to change/buy ship model
@ -34,6 +33,7 @@ Character sheet
* Allow to cancel spent skill points (and confirm when closing the sheet)
* Add filters and sort options for cargo and shop
* Display level and slot type on equipment
* Fixed tooltips not being visible in loot mode (at the end of battle)
Battle
------
@ -93,7 +93,6 @@ Artificial Intelligence
Common UI
---------
* Split atlases by asset stage
* UIBuilder.button should be able to handle hover and pushed images
* If ProgressiveMessage animation performance is bad, show the text directly
* Add caret/focus to text input
@ -104,8 +103,9 @@ Common UI
Technical
---------
* Pack all images in atlases
* Pack all images in atlases, and split them by stage
* Pack sounds
* Use shaders for backgrounds, with fallback images
* Replace jasmine with mocha+chai
Network
@ -126,7 +126,6 @@ Postponed
* Formation or deployment phase
* Add ship personality (with icons to identify?), with reaction dialogs
* New battle internal flow: any game state change should be done through revertable events
* Animated arena background, instead of big picture
* Hide enemy information (shield, hull, weapons), until they are in play, or until a "spy" effect is used
* Invocation/reinforcements (need to up the 10 ships limit)
* Dynamic music composition

View file

@ -124,8 +124,8 @@ module TK.SpaceTac {
*
* This does not check where the equipment currently is (except if is it already attached and should be detached first).
*/
canBeEquipped(skills: ShipAttributes): boolean {
if (this.attached_to) {
canBeEquipped(skills: ShipAttributes, check_unattached = true): boolean {
if (check_unattached && this.attached_to) {
return false;
} else {
var able = true;

View file

@ -12,18 +12,18 @@ module TK.SpaceTac.UI.Specs {
let equipment = new CharacterEquipment(sheet, new Equipment(), source);
let destination = new CharacterCargo(sheet, 0, 0);
expect(destination.addEquipment(equipment, null, true)).toBe(false);
expect(destination.addEquipment(equipment, null, true)).toEqual({ success: false, info: 'put in cargo', error: 'not enough cargo space' });
ship.setCargoSpace(1);
expect(destination.addEquipment(equipment, null, true)).toBe(true);
expect(destination.addEquipment(equipment, null, true)).toEqual({ success: true, info: 'put in cargo' });
ship.critical = true;
expect(destination.addEquipment(equipment, null, true)).toBe(false);
expect(destination.addEquipment(equipment, null, true)).toEqual({ success: false, info: 'put in cargo', error: 'not a fleet member' });
ship.critical = false;
expect(source.removeEquipment(equipment, null, true)).toBe(false);
expect(source.removeEquipment(equipment, null, true)).toEqual({ success: false, info: 'remove from cargo', error: 'not in cargo!' });
ship.addCargo(equipment.item);
expect(source.removeEquipment(equipment, null, true)).toBe(true);
expect(source.removeEquipment(equipment, null, true)).toEqual({ success: true, info: 'remove from cargo' });
ship.critical = true;
expect(source.removeEquipment(equipment, null, true)).toBe(false);
expect(source.removeEquipment(equipment, null, true)).toEqual({ success: false, info: 'remove from cargo', error: 'not a fleet member' });
});
});
}

View file

@ -35,30 +35,34 @@ module TK.SpaceTac.UI {
getPriceOffset(): number {
return 66;
}
addEquipment(equipment: CharacterEquipment, source: CharacterEquipmentContainer | null, test: boolean): boolean {
addEquipment(equipment: CharacterEquipment, source: CharacterEquipmentContainer | null, test: boolean): CharacterEquipmentTransfer {
let info = "put in cargo";
if (this.sheet.ship.critical) {
return false;
return { success: false, info: info, error: "not a fleet member" };
} if (this.sheet.ship.getFreeCargoSpace() > 0) {
if (test) {
return true;
return { success: true, info: info };
} else {
return this.sheet.ship.addCargo(equipment.item);
let success = this.sheet.ship.addCargo(equipment.item);
return { success: success, info: info };
}
} else {
return false;
return { success: false, info: info, error: "not enough cargo space" };
}
}
removeEquipment(equipment: CharacterEquipment, destination: CharacterEquipmentContainer | null, test: boolean): boolean {
removeEquipment(equipment: CharacterEquipment, destination: CharacterEquipmentContainer | null, test: boolean): CharacterEquipmentTransfer {
let info = "remove from cargo";
if (this.sheet.ship.critical) {
return false;
return { success: false, info: info, error: "not a fleet member" };
} else if (contains(this.sheet.ship.cargo, equipment.item)) {
if (test) {
return true;
return { success: true, info: info };
} else {
return this.sheet.ship.removeCargo(equipment.item);
let success = this.sheet.ship.removeCargo(equipment.item);
return { success: success, info: info };
}
} else {
return false;
return { success: false, info: info, error: "not in cargo!" };
}
}
}

View file

@ -23,41 +23,45 @@ module TK.SpaceTac.UI.Specs {
getPriceOffset(): number {
return 12;
}
addEquipment(equipment: CharacterEquipment, source: CharacterEquipmentContainer | null, test: boolean): boolean {
addEquipment(equipment: CharacterEquipment, source: CharacterEquipmentContainer | null, test: boolean): CharacterEquipmentTransfer {
if (this.x < 150) {
if (!test) {
this.inside = equipment;
}
return true;
return { success: true, info: "" };
} else {
return false;
return { success: false, info: "" };
}
}
removeEquipment(equipment: CharacterEquipment, destination: CharacterEquipmentContainer | null, test: boolean): boolean {
removeEquipment(equipment: CharacterEquipment, destination: CharacterEquipmentContainer | null, test: boolean): CharacterEquipmentTransfer {
if (this.inside === equipment) {
if (!test) {
this.inside = null;
}
return true;
return { success: true, info: "" };
} else {
return false;
return { success: false, info: "" };
}
}
}
it("handles drag-and-drop to move equipment", function () {
function createBasicCase(positions: number[]): [CharacterSheet, CharacterEquipment, FakeContainer[], Function] {
let view = testgame.view;
let sheet = new CharacterSheet(view);
sheet.show(new Ship());
let refresh = spyOn(sheet, "refresh").and.stub();
let container1 = new FakeContainer("container1", 0);
let container2 = new FakeContainer("container2", 100);
let container3 = new FakeContainer("container3", 200);
let equipment = new CharacterEquipment(sheet, new Equipment(), container1);
container1.inside = equipment;
let containers = positions.map((x, idx) => new FakeContainer(`container${idx + 1}`, x));
let equipment = new CharacterEquipment(sheet, new Equipment(), containers[0]);
containers[0].inside = equipment;
equipment.setupDragDrop();
spyOn(sheet, "iEquipmentContainers").and.returnValue(iarray([container1, container2, container3]));
spyOn(sheet, "iEquipmentContainers").and.returnValue(iarray(containers));
return [sheet, equipment, containers, refresh];
}
it("handles drag-and-drop to move equipment", function () {
let [sheet, equipment, [container1, container2, container3], refresh] = createBasicCase([0, 100, 200]);
expect(equipment.inputEnabled).toBe(true, "Input should be enabled");
expect(equipment.input.draggable).toBe(true, "Equipment should be draggable");
@ -97,7 +101,7 @@ module TK.SpaceTac.UI.Specs {
// broken destination, should return to source
let log = spyOn(console, "error").and.stub();
spyOn(container3, "addEquipment").and.returnValues(true, false, true, false);
spyOn(container3, "addEquipment").and.callFake((equ: any, src: any, test: boolean) => { return { success: test } });
equipment.events.onDragStart.dispatch();
equipment.x = 200;
equipment.events.onDragStop.dispatch();
@ -107,14 +111,44 @@ module TK.SpaceTac.UI.Specs {
expect(log).toHaveBeenCalledWith('Destination container refused to accept equipment', equipment, container2, container3);
// broken destination and source, item is lost !
spyOn(container2, "addEquipment").and.returnValue(false);
spyOn(container2, "addEquipment").and.callFake((equ: any, src: any, test: boolean) => { return { success: test } });
equipment.events.onDragStart.dispatch();
equipment.x = 200;
equipment.events.onDragStop.dispatch();
expect(equipment.container).toBe(container3);
expect(equipment.x).toBe(200);
expect(refresh).toHaveBeenCalledTimes(2);
expect(log).toHaveBeenCalledWith('Equipment lost in bad exchange !', equipment, container2, container3);
expect(log).toHaveBeenCalledWith('Equipment lost in bad exchange!', equipment, container2, container3);
});
it("defines the sheet's action message", function () {
let [sheet, equipment, [container1, container2], refresh] = createBasicCase([0, 1]);
spyOn(container1, "removeEquipment").and.returnValues(
{ success: true, info: "detach" },
{ success: false, info: "detach", error: "cannot detach" },
{ success: true, info: "detach" },
{ success: false, info: "detach", error: "cannot detach" }
)
spyOn(container2, "addEquipment").and.returnValues(
{ success: true, info: "attach" },
{ success: true, info: "attach" },
{ success: false, info: "attach", error: "cannot attach" },
{ success: false, info: "attach", error: "cannot attach" }
)
expect(sheet.action_message.text).toEqual("");
equipment.events.onDragStart.dispatch();
expect(sheet.action_message.text).toEqual("");
equipment.x = 1;
equipment.events.onDragUpdate.dispatch();
expect(sheet.action_message.text).toEqual("Detach, attach");
equipment.events.onDragUpdate.dispatch();
expect(sheet.action_message.text).toEqual("Detach, attach (cannot detach)");
equipment.events.onDragUpdate.dispatch();
expect(sheet.action_message.text).toEqual("Detach, attach (cannot attach)");
equipment.events.onDragUpdate.dispatch();
expect(sheet.action_message.text).toEqual("Detach, attach (cannot detach)");
});
});
}

View file

@ -18,11 +18,28 @@ module TK.SpaceTac.UI {
/**
* Add an equipment to the container
*/
addEquipment(equipment: CharacterEquipment, source: CharacterEquipmentContainer | null, test: boolean): boolean
addEquipment(equipment: CharacterEquipment, source: CharacterEquipmentContainer | null, test: boolean): CharacterEquipmentTransfer
/**
* Remove an equipment from the container
*/
removeEquipment(equipment: CharacterEquipment, destination: CharacterEquipmentContainer | null, test: boolean): boolean
removeEquipment(equipment: CharacterEquipment, destination: CharacterEquipmentContainer | null, test: boolean): CharacterEquipmentTransfer
}
/**
* Result of an equipment transfer operation
*/
export type CharacterEquipmentTransfer = {
success: boolean,
info: string,
error?: string
}
function mergeTransfer(leave: CharacterEquipmentTransfer, enter: CharacterEquipmentTransfer): CharacterEquipmentTransfer {
return {
success: leave.success && enter.success,
info: [leave.info, enter.info].join(', '),
error: leave.error || enter.error
}
}
/**
@ -104,9 +121,10 @@ module TK.SpaceTac.UI {
this.alpha = 0.8;
}, () => {
// Drop
this.sheet.setActionMessage();
let destination = this.findContainerAt(this.x, this.y);
if (destination && destination != this.container) {
if (this.applyDragDrop(this.container, destination, false)) {
if (this.applyDragDrop(this.container, destination, false).success) {
this.container = destination;
this.snapToContainer();
this.setupDragDrop();
@ -117,6 +135,19 @@ module TK.SpaceTac.UI {
} else {
this.snapToContainer();
}
}, () => {
// Update
let destination = this.findContainerAt(this.x, this.y);
if (destination && destination != this.container) {
let simulation = this.applyDragDrop(this.container, destination, true);
let message = capitalize(simulation.info);
if (simulation.error) {
message += ` (${simulation.error})`;
}
this.sheet.setActionMessage(message, simulation.success ? "#ffffff" : "#f04240");
} else {
this.sheet.setActionMessage();
}
});
} else {
this.sheet.view.inputs.setDragDrop(this);
@ -128,30 +159,39 @@ module TK.SpaceTac.UI {
*
* 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);
applyDragDrop(source: CharacterEquipmentContainer, destination: CharacterEquipmentContainer, test: boolean): CharacterEquipmentTransfer {
let transfer_test = mergeTransfer(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;
return transfer_test;
} else if (transfer_test.success) {
let transfer_out = source.removeEquipment(this, destination, false);
if (transfer_out.success) {
let transfer_in = destination.addEquipment(this, source, false);
let transfer = mergeTransfer(transfer_out, transfer_in);
if (transfer_in.success) {
return transfer;
} else {
console.error("Destination container refused to accept equipment", this, source, destination);
// Go back to source
if (source.addEquipment(this, null, false)) {
return false;
let transfer_back = source.addEquipment(this, null, false);
if (transfer_back.success) {
return transfer;
} else {
console.error("Equipment lost in bad exchange !", this, source, destination);
return true;
console.error("Equipment lost in bad exchange!", this, source, destination);
return {
success: true,
info: transfer.info,
error: "Equipment was critically damaged in transfer!"
};
}
}
} else {
console.error("Source container refused to give away equipment", this, source, destination);
return false;
return transfer_out;
}
} else {
return false;
return transfer_test;
}
}

View file

@ -60,9 +60,9 @@ module TK.SpaceTac.UI.Specs {
// Cannot transfer to escorted ship
ship2.setCargoSpace(2);
expect(equ.applyDragDrop(source, dest, true)).toBe(true);
expect(equ.applyDragDrop(source, dest, true)).toEqual({ success: true, info: 'remove from cargo, transfer to unnamed', error: undefined });
ship2.critical = true;
expect(equ.applyDragDrop(source, dest, true)).toBe(false);
expect(equ.applyDragDrop(source, dest, true)).toEqual({ success: false, info: 'remove from cargo, transfer to unnamed', error: 'not a fleet member' });
});
});
}

View file

@ -41,7 +41,7 @@ module TK.SpaceTac.UI {
* CharacterEquipmentContainer interface
*/
isInside(x: number, y: number): boolean {
return this.getBounds().contains(x, y);
return this.getBounds().contains(x, y) && this.ship !== this.sheet.ship;
}
getEquipmentAnchor(): { x: number, y: number, scale: number, alpha: number } {
// not needed, equipment is never shown snapped in the slot
@ -50,35 +50,41 @@ module TK.SpaceTac.UI {
getPriceOffset(): number {
return 0;
}
addEquipment(equipment: CharacterEquipment, source: CharacterEquipmentContainer | null, test: boolean): boolean {
addEquipment(equipment: CharacterEquipment, source: CharacterEquipmentContainer | null, test: boolean): CharacterEquipmentTransfer {
let info = `transfer to ${this.ship.name}`;
if (this.ship.critical) {
return false;
return { success: false, info: info, error: "not a fleet member" };
} else if (this.ship != this.sheet.ship && equipment.item.slot_type !== null) {
// First, try to equip
let slot = this.ship.getFreeSlot(equipment.item.slot_type);
if (slot) {
if (slot && equipment.item.canBeEquipped(this.ship.attributes, false)) {
info = `equip on ${this.ship.name}`;
if (test) {
return true;
return { success: true, info: info };
} 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;
let success = this.ship.equip(equipment.item, false);
return { success: true, info: info };
}
}
// If cannot be equipped, go to cargo
if (this.ship.getFreeCargoSpace() > 0) {
if (test) {
return { success: true, info: info };
} else {
let success = this.ship.addCargo(equipment.item);
return { success: success, info: info };
}
} else {
return { success: false, info: info, error: "not enough cargo space" };
}
} else {
return false;
return { success: false, info: info, error: "drop on cargo or slots" };
}
}
removeEquipment(equipment: CharacterEquipment, destination: CharacterEquipmentContainer | null, test: boolean): boolean {
removeEquipment(equipment: CharacterEquipment, destination: CharacterEquipmentContainer | null, test: boolean): CharacterEquipmentTransfer {
// should never happen
return false;
return { success: false, info: "" };
}
}
}

View file

@ -6,21 +6,23 @@ module TK.SpaceTac.UI {
* Display a loot slot
*/
export class CharacterLootSlot extends CharacterCargo {
addEquipment(equipment: CharacterEquipment, source: CharacterEquipmentContainer | null, test: boolean): boolean {
addEquipment(equipment: CharacterEquipment, source: CharacterEquipmentContainer | null, test: boolean): CharacterEquipmentTransfer {
if (!test) {
add(this.sheet.loot_items, equipment.item);
}
return true;
return { success: true, info: "leave equipment" };
}
removeEquipment(equipment: CharacterEquipment, destination: CharacterEquipmentContainer | null, test: boolean): boolean {
removeEquipment(equipment: CharacterEquipment, destination: CharacterEquipmentContainer | null, test: boolean): CharacterEquipmentTransfer {
let info = "Loot equipment";
if (contains(this.sheet.loot_items, equipment.item)) {
if (test) {
return true;
return { success: true, info: info };
} else {
return remove(this.sheet.loot_items, equipment.item);
let success = remove(this.sheet.loot_items, equipment.item);
return { success: success, info: info };
}
} else {
return false;
return { success: false, info: info, error: "not lootable!" };
}
}
}

View file

@ -44,8 +44,9 @@ module TK.SpaceTac.UI {
// Ship cargo
ship_cargo: Phaser.Group
// Mode title
mode_title: Phaser.Text
// Dynamic texts
mode_title: UIText
action_message: UIText
// Loot items
loot_slots: Phaser.Group
@ -88,6 +89,7 @@ module TK.SpaceTac.UI {
this.close_button = this.builder.button("character-close", 1920, 0, onclose, "Close the character sheet");
this.close_button.anchor.set(1, 0);
this.builder.text("Cargo", 1566, 36, { size: 24 });
this.builder.text("Level", 420, 1052, { size: 24 });
this.builder.text("Available points", 894, 1052, { size: 24 });
@ -101,6 +103,7 @@ module TK.SpaceTac.UI {
this.portraits = this.builder.group("portraits", 152, 0);
this.credits = this.builder.text("", 136, 38, { size: 30 });
this.mode_title = this.builder.text("", 1566, 648, { size: 18 });
this.action_message = this.builder.text("", 1566, 1056, { size: 18 });
this.loot_next = this.builder.button("common-arrow-right", 1890, 850, () => this.paginate(1), "Show next items");
this.loot_next.anchor.set(0.5);
this.loot_prev = this.builder.button("common-arrow-left", 1238, 850, () => this.paginate(-1), "Show previous items");
@ -189,6 +192,7 @@ module TK.SpaceTac.UI {
this.ship = ship;
this.layer_equipments.removeAll(true);
this.setActionMessage();
let upgrade_points = ship.getAvailableUpgradePoints();
@ -211,11 +215,11 @@ module TK.SpaceTac.UI {
let slot_display = new CharacterSlot(this, slotsinfo.positions[idx].x, slotsinfo.positions[idx].y, slot.type);
slot_display.scale.set(slotsinfo.scaling, slotsinfo.scaling);
slot_display.alpha = ship.critical ? 0.5 : 1;
this.ship_slots.addChild(slot_display);
this.ship_slots.add(slot_display);
if (slot.attached) {
let equipment = new CharacterEquipment(this, slot.attached, slot_display);
this.layer_equipments.addChild(equipment);
this.layer_equipments.add(equipment);
}
});
@ -225,11 +229,11 @@ module TK.SpaceTac.UI {
let cargo_slot = new CharacterCargo(this, slotsinfo.positions[idx].x, slotsinfo.positions[idx].y);
cargo_slot.scale.set(slotsinfo.scaling, slotsinfo.scaling);
cargo_slot.alpha = ship.critical ? 0.5 : 1;
this.ship_cargo.addChild(cargo_slot);
this.ship_cargo.add(cargo_slot);
if (idx < this.ship.cargo.length) {
let equipment = new CharacterEquipment(this, this.ship.cargo[idx], cargo_slot);
this.layer_equipments.addChild(equipment);
this.layer_equipments.add(equipment);
}
});
@ -273,6 +277,16 @@ module TK.SpaceTac.UI {
}
}
/**
* Set the action message (mainly used while dragging equipment to explain what is happening)
*/
setActionMessage(message = "", color = "#ffffff"): void {
if (message != this.action_message.text) {
this.action_message.setText(message);
this.action_message.fill = color;
}
}
/**
* Set the list of lootable equipment
*
@ -337,13 +351,13 @@ module TK.SpaceTac.UI {
range(per_page).forEach(idx => {
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);
loot_slot.scale.set(info.scaling, info.scaling);
this.loot_slots.addChild(loot_slot);
this.loot_slots.add(loot_slot);
idx += per_page * this.loot_page;
if (idx < items.length) {
let equipment = new CharacterEquipment(this, items[idx], loot_slot);
this.layer_equipments.addChild(equipment);
this.layer_equipments.add(equipment);
}
});

View file

@ -5,34 +5,41 @@ module TK.SpaceTac.UI {
* Display a shop slot
*/
export class CharacterShopSlot extends CharacterLootSlot {
addEquipment(equipment: CharacterEquipment, source: CharacterEquipmentContainer | null, test: boolean): boolean {
addEquipment(equipment: CharacterEquipment, source: CharacterEquipmentContainer | null, test: boolean): CharacterEquipmentTransfer {
let shop = this.sheet.shop;
if (shop && !contains(shop.getStock(), equipment.item)) {
let price = shop.getPrice(equipment.item);
let info = `sell for ${price} zotys`;
if (test) {
return true;
return { success: true, info: info };
} else {
return shop.buyFromFleet(equipment.item, this.sheet.fleet);
let success = shop.buyFromFleet(equipment.item, this.sheet.fleet);
return { success: success, info: info };
}
} else {
return false;
return { success: false, info: "sell equipment", error: "it's already mine!" };
}
}
removeEquipment(equipment: CharacterEquipment, destination: CharacterEquipmentContainer | null, test: boolean): boolean {
removeEquipment(equipment: CharacterEquipment, destination: CharacterEquipmentContainer | null, test: boolean): CharacterEquipmentTransfer {
let shop = this.sheet.shop;
if (shop && contains(shop.getStock(), equipment.item)) {
let price = shop.getPrice(equipment.item);
let info = `buy for ${price} zotys`;
if (destination) {
let price = shop.getPrice(equipment.item);
if (test) {
return price <= this.sheet.fleet.credits;
if (price > this.sheet.fleet.credits) {
return { success: false, info: info, error: "not enough zotys" };
} else if (test) {
return { success: true, info: info };
} else {
return shop.sellToFleet(equipment.item, this.sheet.fleet);
let success = shop.sellToFleet(equipment.item, this.sheet.fleet);
return { success: success, info: info };
}
} else {
return test;
return { success: test, info: info };
}
} else {
return false;
return { success: false, info: "buy equipment", error: "it's not mine to sell!" };
}
}
}

View file

@ -13,34 +13,34 @@ module TK.SpaceTac.UI.Specs {
let equipment = new CharacterEquipment(sheet, new Equipment(SlotType.Engine), source);
let slot = new CharacterSlot(sheet, 0, 0, SlotType.Engine);
expect(slot.addEquipment(equipment, source, true)).toBe(false);
expect(slot.removeEquipment(equipment, source, true)).toBe(false);
expect(slot.addEquipment(equipment, source, true)).toEqual({ success: false, info: 'equip in engine slot', error: 'no free slot' });
expect(slot.removeEquipment(equipment, source, true)).toEqual({ success: false, info: 'unequip from engine slot', error: 'not equipped!' });
ship.addSlot(SlotType.Engine);
expect(slot.addEquipment(equipment, source, true)).toBe(true);
expect(slot.addEquipment(equipment, source, true)).toEqual({ success: true, info: 'equip in engine slot' });
equipment.item.requirements["skill_time"] = 1;
expect(slot.addEquipment(equipment, source, true)).toBe(false);
expect(slot.addEquipment(equipment, source, true)).toEqual({ success: false, info: 'equip in engine slot', error: 'missing skills' });
ship.upgradeSkill("skill_time");
expect(slot.addEquipment(equipment, source, true)).toBe(true);
expect(slot.addEquipment(equipment, source, true)).toEqual({ success: true, info: 'equip in engine slot' });
ship.critical = true;
expect(slot.addEquipment(equipment, source, true)).toBe(false);
expect(slot.addEquipment(equipment, source, true)).toEqual({ success: false, info: 'equip in engine slot', error: 'not a fleet member' });
ship.critical = false;
expect(ship.listEquipment(SlotType.Engine)).toEqual([]);
let result = slot.addEquipment(equipment, source, false);
expect(result).toBe(true);
expect(result).toEqual({ success: true, info: 'equip in engine slot' });
expect(ship.listEquipment(SlotType.Engine)).toEqual([equipment.item]);
expect(slot.removeEquipment(equipment, source, true)).toBe(true);
expect(slot.removeEquipment(equipment, source, true)).toEqual({ success: true, info: 'unequip from engine slot' });
ship.critical = true;
expect(slot.removeEquipment(equipment, source, true)).toBe(false);
expect(slot.removeEquipment(equipment, source, true)).toEqual({ success: false, info: 'unequip from engine slot', error: 'not a fleet member' });
ship.critical = false;
result = slot.removeEquipment(equipment, source, false);
expect(result).toBe(true);
expect(result).toEqual({ success: true, info: 'unequip from engine slot' });
expect(ship.listEquipment(SlotType.Engine)).toEqual([]);
});

View file

@ -37,30 +37,36 @@ module TK.SpaceTac.UI {
getPriceOffset(): number {
return 66;
}
addEquipment(equipment: CharacterEquipment, source: CharacterEquipmentContainer | null, test: boolean): boolean {
addEquipment(equipment: CharacterEquipment, source: CharacterEquipmentContainer | null, test: boolean): CharacterEquipmentTransfer {
let info = equipment.item.slot_type ? `equip in ${SlotType[equipment.item.slot_type].toLowerCase()} slot` : "equip";
if (this.sheet.ship.critical) {
return false;
} if (this.sheet.ship.canEquip(equipment.item)) {
if (test) {
return true;
} else {
return this.sheet.ship.equip(equipment.item, false);
}
return { success: false, info: info, error: "not a fleet member" };
} else if (!equipment.item.canBeEquipped(this.sheet.ship.attributes, false)) {
return { success: false, info: info, error: "missing skills" };
} else if (equipment.item.slot_type && !this.sheet.ship.getFreeSlot(equipment.item.slot_type)) {
return { success: false, info: info, error: "no free slot" };
} else {
return false;
if (test) {
return { success: true, info: info };
} else {
let success = this.sheet.ship.equip(equipment.item, false);
return { success: success, info: info };
}
}
}
removeEquipment(equipment: CharacterEquipment, destination: CharacterEquipmentContainer | null, test: boolean): boolean {
removeEquipment(equipment: CharacterEquipment, destination: CharacterEquipmentContainer | null, test: boolean): CharacterEquipmentTransfer {
let info = equipment.item.slot_type ? `unequip from ${SlotType[equipment.item.slot_type].toLowerCase()} slot` : "unequip";
if (this.sheet.ship.critical) {
return false;
} if (contains(this.sheet.ship.listEquipment(equipment.item.slot_type), equipment.item)) {
if (test) {
return true;
} else {
return this.sheet.ship.unequip(equipment.item, false);
}
return { success: false, info: info, error: "not a fleet member" };
} if (!contains(this.sheet.ship.listEquipment(equipment.item.slot_type), equipment.item)) {
return { success: false, info: info, error: "not equipped!" };
} else {
return false;
if (test) {
return { success: true, info: info };
} else {
let success = this.sheet.ship.unequip(equipment.item, false);
return { success: success, info: info };
}
}
}
}

View file

@ -27,7 +27,7 @@ module TK.SpaceTac.UI {
this.infinite_shop = new Shop(1, basic_equipments(), 0, basic_equipments);
this.character_sheet = new CharacterSheet(this, undefined, undefined, () => this.validateFleet());
this.character_sheet.setShop(this.infinite_shop, "Initial basic equipment");
this.character_sheet.setShop(this.infinite_shop, "Available stock (from Master Merchant Guild)");
this.character_sheet.show(this.built_fleet.ships[0], false);
this.getLayer("characters").add(this.character_sheet);
}

View file

@ -135,10 +135,13 @@ module TK.SpaceTac.UI {
* Setup dragging on an UI component
*
* If no drag or drop function is defined, dragging is disabled
*
* If update function is defined, it will receive (a lot of) cursor moves while dragging
*/
setDragDrop(obj: Phaser.Button | Phaser.Image, drag?: Function, drop?: Function): void {
setDragDrop(obj: Phaser.Button | Phaser.Image, drag?: Function, drop?: Function, update?: Function): void {
obj.events.onDragStart.removeAll();
obj.events.onDragStop.removeAll();
obj.events.onDragUpdate.removeAll();
if (drag && drop) {
obj.inputEnabled = true;
@ -149,10 +152,17 @@ module TK.SpaceTac.UI {
this.view.audio.playOnce("ui-drag");
drag();
});
obj.events.onDragStop.add(() => {
this.view.audio.playOnce("ui-drop");
drop();
});
if (update) {
obj.events.onDragUpdate.add(() => {
update();
});
}
} else {
obj.input.disableDrag();
}