1
0
Fork 0

Added ability to equip/unequip from character sheet

This commit is contained in:
Michaël Lemaire 2017-03-06 00:29:02 +01:00
parent 0cdc7b3def
commit 80e3f212d6
8 changed files with 264 additions and 23 deletions

@ -1 +1 @@
Subproject commit ce9feb35874b0aa2686c80f1b7f56447044b9d74
Subproject commit db61f921e8afa9beca31bf1de1d30870f48a17e4

View file

@ -308,5 +308,92 @@ module TS.SpaceTac.Specs {
expect(onTurnEnd).toHaveBeenCalledWith(ship);
expect(onShipMove).toHaveBeenCalledTimes(1);
});
it("stores items in cargo space", function () {
let ship = new Ship();
let equipment1 = new Equipment();
let equipment2 = new Equipment();
let result = ship.addCargo(equipment1);
expect(result).toBe(false);
expect(ship.cargo).toEqual([]);
ship.setCargoSpace(1);
result = ship.addCargo(equipment1);
expect(result).toBe(true);
expect(ship.cargo).toEqual([equipment1]);
result = ship.addCargo(equipment1);
expect(result).toBe(false);
expect(ship.cargo).toEqual([equipment1]);
result = ship.addCargo(equipment2);
expect(result).toBe(false);
expect(ship.cargo).toEqual([equipment1]);
ship.setCargoSpace(2);
result = ship.addCargo(equipment2);
expect(result).toBe(true);
expect(ship.cargo).toEqual([equipment1, equipment2]);
ship.setCargoSpace(1);
expect(ship.cargo).toEqual([equipment1]);
ship.setCargoSpace(2);
expect(ship.cargo).toEqual([equipment1]);
});
it("equips items from cargo", function () {
let ship = new Ship();
let equipment = new Equipment(SlotType.Weapon);
let slot = ship.addSlot(SlotType.Weapon);
expect(ship.listEquipment()).toEqual([]);
let result = ship.equip(equipment);
expect(result).toBe(false);
expect(ship.listEquipment()).toEqual([]);
ship.setCargoSpace(1);
ship.addCargo(equipment);
result = ship.equip(equipment);
expect(result).toBe(true);
expect(ship.listEquipment(SlotType.Weapon)).toEqual([equipment]);
expect(equipment.attached_to).toEqual(slot);
});
it("removes equipped items", function () {
let ship = new Ship();
let equipment = new Equipment(SlotType.Weapon);
let slot = ship.addSlot(SlotType.Weapon);
slot.attach(equipment);
expect(ship.listEquipment()).toEqual([equipment]);
expect(slot.attached).toBe(equipment);
expect(equipment.attached_to).toBe(slot);
let result = ship.unequip(equipment);
expect(result).toBe(false);
expect(ship.listEquipment()).toEqual([equipment]);
expect(ship.cargo).toEqual([]);
ship.setCargoSpace(10);
result = ship.unequip(equipment);
expect(result).toBe(true);
expect(ship.listEquipment()).toEqual([]);
expect(ship.cargo).toEqual([equipment]);
expect(slot.attached).toBe(null);
expect(equipment.attached_to).toBe(null);
result = ship.unequip(equipment);
expect(result).toBe(false);
expect(ship.listEquipment()).toEqual([]);
expect(ship.cargo).toEqual([equipment]);
});
});
}

View file

@ -443,26 +443,74 @@ module TS.SpaceTac {
*/
setCargoSpace(cargo: number) {
this.cargo_space = cargo;
this.cargo.splice(this.cargo_space);
}
// Add an empty equipment slot of the given type
/**
* Add an equipment to cargo space
*
* Returns true if successful
*/
addCargo(item: Equipment): boolean {
if (this.cargo.length < this.cargo_space) {
return add(this.cargo, item);
} else {
return false;
}
}
/**
* Equip an item from cargo to the first available slot
*
* Returns true if successful
*/
equip(item: Equipment): 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);
free_slot.attach(item);
this.updateAttributes();
return true;
} else {
return false;
}
}
/**
* Remove an equipped item, returning it to cargo
*
* Returns true if successful
*/
unequip(item: Equipment): boolean {
if (item.attached_to && item.attached_to.attached == item && this.cargo.length < this.cargo_space) {
item.detach();
add(this.cargo, item);
this.updateAttributes();
return true;
} else {
return false;
}
}
/**
* Add an empty equipment slot of the given type
*/
addSlot(type: SlotType): Slot {
var result = new Slot(this, type);
this.slots.push(result);
return result;
}
// List all attached equipments of a given type (all types if null)
listEquipment(slottype: SlotType = null): Equipment[] {
var result: Equipment[] = [];
this.slots.forEach((slot: Slot) => {
if (slot.type === slottype && slot.attached) {
result.push(slot.attached);
}
});
return result;
/**
* List all equipments attached to slots of a given type (any slot type if null)
*/
listEquipment(slottype: SlotType | null = null): Equipment[] {
return this.slots.filter(slot => slot.attached && (slottype == null || slot.type == slottype)).map(slot => slot.attached);
}
// Get the number of attached equipments

View file

@ -171,8 +171,9 @@ module TS.SpaceTac.UI {
cursorClicked(): void {
if (this.targetting) {
this.targetting.validate();
} else if (this.ship_hovered) {
} else if (this.ship_hovered && this.ship_hovered.getPlayer() == this.player) {
this.character_sheet.show(this.ship_hovered);
this.setShipHovered(null);
}
}

View file

@ -3,16 +3,33 @@ module TS.SpaceTac.UI {
* Display a ship cargo slot
*/
export class CharacterCargo extends Phaser.Image {
sheet: CharacterSheet;
constructor(sheet: CharacterSheet, x: number, y: number) {
super(sheet.game, x, y, "character-cargo-slot");
this.sheet = sheet;
}
/**
* Set the equipment displayed in the slot
* Snap the equipment icon inside the slot
*/
setEquipment(equipment: CharacterEquipment | null) {
this.addChild(equipment);
equipment.position.set(98, 98);
snapEquipment(equipment: CharacterEquipment) {
equipment.position.set(this.x + this.parent.x + 98, this.y + this.parent.y + 98);
}
/**
* 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)) {
return {
message: "Unequip",
callback: () => this.sheet.ship.unequip(equipment)
};
} else {
return null;
}
}
}
}

View file

@ -1,4 +1,11 @@
module TS.SpaceTac.UI {
/**
* Interface for any graphical item that may receive an equipment as drop destination
*/
export interface CharacterEquipmentDestination {
canDropEquipment(equipment: Equipment, x: number, y: number): CharacterEquipmentDrop | null;
}
/**
* Display a ship equipment, either attached to a slot, in cargo, or being dragged down
*/
@ -9,6 +16,31 @@ module TS.SpaceTac.UI {
this.anchor.set(0.5, 0.5);
this.scale.set(0.5, 0.5);
this.inputEnabled = true;
this.input.enableDrag(false, true);
let origin: [number, number] | null = null;
let drop: CharacterEquipmentDrop | null = null;
this.events.onDragStart.add(() => {
origin = [this.x, this.y];
this.alpha = 0.8;
});
this.events.onDragUpdate.add(() => {
drop = sheet.canDropEquipment(equipment, this.x, this.y);
});
this.events.onDragStop.add(() => {
if (drop) {
drop.callback(equipment);
sheet.refresh();
} else {
if (origin) {
this.position.set(origin[0], origin[1]);
origin = null;
}
this.alpha = 1;
}
});
}
}
}

View file

@ -1,4 +1,9 @@
module TS.SpaceTac.UI {
export type CharacterEquipmentDrop = {
message: string
callback: (equipment: Equipment) => any
}
/**
* Character sheet, displaying ship characteristics
*/
@ -31,6 +36,9 @@ module TS.SpaceTac.UI {
// Fleet's portraits
portraits: Phaser.Group;
// Layer for draggable equipments
equipments: Phaser.Group;
// Credits
credits: Phaser.Text;
@ -77,6 +85,9 @@ module TS.SpaceTac.UI {
this.credits.anchor.set(0.5, 0.5);
this.addChild(this.credits);
this.equipments = new Phaser.Group(this.game);
this.addChild(this.equipments);
let x1 = 664;
let x2 = 1066;
let y = 662;
@ -142,6 +153,8 @@ module TS.SpaceTac.UI {
show(ship: Ship, animate = true) {
this.ship = ship;
this.equipments.removeAll(true);
this.ship_name.setText(ship.name);
this.ship_level.setText(ship.level.toString());
this.ship_upgrades.setText(ship.upgrade_points.toString());
@ -162,7 +175,8 @@ module TS.SpaceTac.UI {
if (slot.attached) {
let equipment = new CharacterEquipment(this, slot.attached);
slot_display.setEquipment(equipment);
this.equipments.addChild(equipment);
slot_display.snapEquipment(equipment);
}
});
@ -172,6 +186,12 @@ module TS.SpaceTac.UI {
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);
if (idx < this.ship.cargo.length) {
let equipment = new CharacterEquipment(this, this.ship.cargo[idx]);
this.equipments.addChild(equipment);
cargo_slot.snapEquipment(equipment);
}
});
this.updateFleet(ship.fleet);
@ -196,6 +216,25 @@ module TS.SpaceTac.UI {
}
}
/**
* Check if an equipment can be dropped somewhere
*/
canDropEquipment(equipment: Equipment, x: number, y: number): CharacterEquipmentDrop | null {
let candidates: Iterator<CharacterEquipmentDestination> = ichain(
iarray(<CharacterSlot[]>this.ship_slots.children),
iarray(<CharacterCargo[]>this.ship_cargo.children)
);
return ifirstmap(candidates, candidate => candidate.canDropEquipment(equipment, x, y));
}
/**
* Refresh the sheet display
*/
refresh() {
this.show(this.ship);
}
/**
* Get the positions and scaling for slots, to fit in a rectangle group.
*/

View file

@ -3,20 +3,37 @@ module TS.SpaceTac.UI {
* Display a ship slot, with equipment attached to it
*/
export class CharacterSlot extends Phaser.Image {
sheet: CharacterSheet;
constructor(sheet: CharacterSheet, x: number, y: number, slot: SlotType) {
super(sheet.game, x, y, "character-equipment-slot");
this.sheet = sheet;
let sloticon = new Phaser.Image(this.game, 150, 150, `character-slot-${SlotType[slot].toLowerCase()}`);
sloticon.anchor.set(0.5, 0.5);
this.addChild(sloticon);
}
/**
* Set the equipment displayed in the slot
* Snap the equipment icon inside the slot
*/
setEquipment(equipment: CharacterEquipment | null) {
this.addChild(equipment);
equipment.position.set(84, 83);
snapEquipment(equipment: CharacterEquipment) {
equipment.position.set(this.x + this.parent.x + 84, this.y + this.parent.y + 83);
}
/**
* 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)) {
return {
message: "Equip",
callback: () => this.sheet.ship.equip(equipment)
};
} else {
return null;
}
}
}
}