From b8bfbb8063c55afa992bcbb29972f500b2545126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Thu, 13 Jul 2017 01:18:20 +0200 Subject: [PATCH] character sheet: Added tooltips for attributes with description and sources (WIP) --- TODO.md | 2 +- src/core/Ship.spec.ts | 20 +++++++ src/core/Ship.ts | 88 +++++++++++++----------------- src/core/ShipAttribute.ts | 16 ------ src/core/ShipValue.ts | 79 +++++++++++++++++++++++++++ src/ui/character/CharacterSheet.ts | 22 +++++--- src/ui/character/CharacterSlot.ts | 3 +- 7 files changed, 154 insertions(+), 76 deletions(-) delete mode 100644 src/core/ShipAttribute.ts diff --git a/TODO.md b/TODO.md index f32d1a6..70298d4 100644 --- a/TODO.md +++ b/TODO.md @@ -26,7 +26,7 @@ Character sheet * Highlight allowed destinations during drag-and-drop, with text hints * When transferring to another ship, if the item can't be equipped (unmatched requirements), the transfer is cancelled instead of trying cargo * Effective skill is sometimes not updated when upgrading base skill -* Tooltip to show the sources of attributes +* Tooltip to show the sources of attributes [WIP] * Forbid to modify escorted ship * Add merged cargo display for the whole fleet diff --git a/src/core/Ship.spec.ts b/src/core/Ship.spec.ts index 64d2869..eb020a6 100644 --- a/src/core/Ship.spec.ts +++ b/src/core/Ship.spec.ts @@ -576,5 +576,25 @@ module TS.SpaceTac.Specs { new AttributeLimitEffect("precision", 2) ]); }); + + it("gets a textual description of an attribute", function () { + let ship = new Ship(); + expect(ship.getAttributeDescription("skill_photons")).toEqual("Forces of light, and electromagnetic radiation"); + + let equipment = new Equipment(SlotType.Engine); + equipment.effects = [new AttributeEffect("skill_photons", 4)]; + equipment.name = "Photonic engine"; + ship.addSlot(SlotType.Engine).attach(equipment); + expect(ship.getAttribute("skill_photons")).toBe(4); + expect(ship.getAttributeDescription("skill_photons")).toEqual("Forces of light, and electromagnetic radiation\n\nPhotonic engine Mk1: +4"); + + ship.level.forceLevelUp(); + ship.upgradeSkill("skill_photons"); + ship.upgradeSkill("skill_photons"); + expect(ship.getAttributeDescription("skill_photons")).toEqual("Forces of light, and electromagnetic radiation\n\nLevelled up: +2\nPhotonic engine Mk1: +4"); + + ship.addStickyEffect(new StickyEffect(new AttributeLimitEffect("skill_photons", 3))); + expect(ship.getAttributeDescription("skill_photons")).toEqual("Forces of light, and electromagnetic radiation\n\nLevelled up: +2\nPhotonic engine Mk1: +4\n???: limit to 3"); + }); }); } diff --git a/src/core/Ship.ts b/src/core/Ship.ts index 5f48411..ebc0e93 100644 --- a/src/core/Ship.ts +++ b/src/core/Ship.ts @@ -1,55 +1,4 @@ -/// -/// - module TS.SpaceTac { - - /** - * Set of upgradable skills for a ship - */ - export class ShipSkills { - // Skills - skill_materials = new ShipAttribute("materials skill") - skill_photons = new ShipAttribute("photons skill") - skill_antimatter = new ShipAttribute("antimatter skill") - skill_quantum = new ShipAttribute("quantum skill") - skill_gravity = new ShipAttribute("gravity skill") - skill_time = new ShipAttribute("time skill") - } - - /** - * Set of ShipAttribute for a ship - */ - export class ShipAttributes extends ShipSkills { - // Maximal hull value - hull_capacity = new ShipAttribute("hull capacity") - // Maximal shield value - shield_capacity = new ShipAttribute("shield capacity") - // Maximal power value - power_capacity = new ShipAttribute("power capacity") - // Power value recovered each turn - power_generation = new ShipAttribute("power generation") - // Ability to move first and fast - maneuvrability = new ShipAttribute("maneuvrability") - // Ability to fire far and good - precision = new ShipAttribute("precision") - } - - /** - * Set of ShipValue for a ship - */ - export class ShipValues { - hull = new ShipValue("hull") - shield = new ShipValue("shield") - power = new ShipValue("power") - } - - /** - * Static attributes and values object for name queries - */ - export const SHIP_SKILLS = new ShipSkills(); - export const SHIP_ATTRIBUTES = new ShipAttributes(); - export const SHIP_VALUES = new ShipValues(); - /** * A single ship in a fleet */ @@ -783,5 +732,42 @@ module TS.SpaceTac { private collectEffects(code: string): BaseEffect[] { return imaterialize(ifilter(this.ieffects(), effect => effect.code == code)); } + + /** + * Get a textual description of an attribute, and the origin of its value + */ + getAttributeDescription(attribute: keyof ShipAttributes): string { + let result = this.attributes[attribute].description; + + let diffs: string[] = []; + let limits: string[] = []; + + function addEffect(base: string, effect: BaseEffect) { + if (effect instanceof AttributeEffect && effect.attrcode == attribute) { + diffs.push(`${base}: ${effect.value > 0 ? "+" + effect.value.toString() : effect.value}`); + } else if (effect instanceof AttributeLimitEffect && effect.attrcode == attribute) { + limits.push(`${base}: limit to ${effect.value}`); + } + } + + if (attribute in this.skills) { + let skill = this.skills[attribute]; + if (skill.get()) { + diffs.push(`Levelled up: +${skill.get()}`); + } + } + + this.slots.forEach(slot => { + if (slot.attached) { + let equipment = slot.attached; + equipment.effects.forEach(effect => addEffect(equipment.getFullName(), effect)); + } + }); + + this.sticky_effects.forEach(effect => addEffect("???", effect.base)); + + let sources = diffs.concat(limits).join("\n"); + return sources ? (result + "\n\n" + sources) : result; + } } } diff --git a/src/core/ShipAttribute.ts b/src/core/ShipAttribute.ts deleted file mode 100644 index f5e241c..0000000 --- a/src/core/ShipAttribute.ts +++ /dev/null @@ -1,16 +0,0 @@ -/// - -module TS.SpaceTac { - /** - * A ship attribute is a value computed by a sum of contributions from equipments and sticky effects. - * - * A value may be limited by other effects. - */ - export class ShipAttribute extends ShipValue { - // Raw contributions value (without limits) - private raw = 0 - - // Temporary limits - private limits: number[] = [] - } -} diff --git a/src/core/ShipValue.ts b/src/core/ShipValue.ts index a01f8b5..d07e2fd 100644 --- a/src/core/ShipValue.ts +++ b/src/core/ShipValue.ts @@ -1,4 +1,19 @@ module TS.SpaceTac { + const SHIP_VALUES_DESCRIPTIONS: { [name: string]: string } = { + "materials skill": "Usage of physical materials such as bullets, shells...", + "photons skill": "Forces of light, and electromagnetic radiation", + "antimatter skill": "Manipulation of matter and antimatter particles", + "quantum skill": "Application of quantum uncertainty principle", + "gravity skill": "Interaction with gravitational forces", + "time skill": "Control of relativity's time properties", + "hull capacity": "Maximal Hull value before the ship risks collapsing", + "shield capacity": "Maximal Shield value to protect the hull from damage", + "power capacity": "Maximal Power value to use equipment", + "power generation": "Power generated at the end of the ship's turn", + "maneuvrability": "Ability to move first and fast", + "precision": "Ability to target far and good", + } + /** * A ship value is a number that may vary and be constrained in a given range. */ @@ -18,6 +33,10 @@ module TS.SpaceTac { this.maximal = maximal; } + get description(): string { + return SHIP_VALUES_DESCRIPTIONS[this.name]; + } + /** * Get the current value */ @@ -76,4 +95,64 @@ module TS.SpaceTac { } } } + + /** + * A ship attribute is a value computed by a sum of contributions from equipments and sticky effects. + * + * A value may be limited by other effects. + */ + export class ShipAttribute extends ShipValue { + // Raw contributions value (without limits) + private raw = 0 + + // Temporary limits + private limits: number[] = [] + } + + /** + * Set of upgradable skills for a ship + */ + export class ShipSkills { + // Skills + skill_materials = new ShipAttribute("materials skill") + skill_photons = new ShipAttribute("photons skill") + skill_antimatter = new ShipAttribute("antimatter skill") + skill_quantum = new ShipAttribute("quantum skill") + skill_gravity = new ShipAttribute("gravity skill") + skill_time = new ShipAttribute("time skill") + } + + /** + * Set of ShipAttribute for a ship + */ + export class ShipAttributes extends ShipSkills { + // Maximal hull value + hull_capacity = new ShipAttribute("hull capacity") + // Maximal shield value + shield_capacity = new ShipAttribute("shield capacity") + // Maximal power value + power_capacity = new ShipAttribute("power capacity") + // Power value recovered each turn + power_generation = new ShipAttribute("power generation") + // Ability to move first and fast + maneuvrability = new ShipAttribute("maneuvrability") + // Ability to fire far and good + precision = new ShipAttribute("precision") + } + + /** + * Set of ShipValue for a ship + */ + export class ShipValues { + hull = new ShipValue("hull") + shield = new ShipValue("shield") + power = new ShipValue("power") + } + + /** + * Static attributes and values object for name queries + */ + export const SHIP_SKILLS = new ShipSkills(); + export const SHIP_ATTRIBUTES = new ShipAttributes(); + export const SHIP_VALUES = new ShipValues(); } diff --git a/src/ui/character/CharacterSheet.ts b/src/ui/character/CharacterSheet.ts index 77cb77f..9c4bf50 100644 --- a/src/ui/character/CharacterSheet.ts +++ b/src/ui/character/CharacterSheet.ts @@ -158,22 +158,30 @@ module TS.SpaceTac.UI { let attrname = capitalize(SHIP_ATTRIBUTES[attribute].name); let name = new Phaser.Text(this.game, x - 144, y - 2, attrname, { align: "center", font: "20pt Arial", fill: "#c9d8ef", stroke: "#395665", strokeThickness: 1 }); - name.anchor.set(0.5, 0.5); + name.anchor.set(0.5); this.addChild(name); - let text = new Phaser.Text(this.game, x, y, "", - { align: "center", font: "bold 18pt Arial", fill: "#FFFFFF" }); - text.anchor.set(0.5, 0.5); - this.addChild(text); + let button_value = new Phaser.Button(this.game, x, y, "common-transparent"); + button_value.input.useHandCursor = false; + button_value.anchor.set(0.5); + button_value.width = 58; + button_value.height = 42; + this.addChild(button_value); + this.view.tooltip.bindDynamicText(button_value, () => this.ship.getAttributeDescription(attribute)); - this.attributes[attribute] = text; + let value = new Phaser.Text(this.game, x, y, "", + { align: "center", font: "bold 18pt Arial", fill: "#FFFFFF" }); + value.anchor.set(0.5); + this.addChild(value); + + this.attributes[attribute] = value; if (SHIP_SKILLS.hasOwnProperty(attribute)) { let button = new Phaser.Button(this.game, x + 54, y - 4, "character-skill-upgrade", () => { this.ship.upgradeSkill(attribute); this.refresh(); }); - button.anchor.set(0.5, 0.5); + button.anchor.set(0.5); this.ship_upgrades.add(button); this.view.tooltip.bindStaticText(button, `Spend one point to upgrade ${attrname}`); diff --git a/src/ui/character/CharacterSlot.ts b/src/ui/character/CharacterSlot.ts index e51fe79..490d76b 100644 --- a/src/ui/character/CharacterSlot.ts +++ b/src/ui/character/CharacterSlot.ts @@ -12,7 +12,8 @@ module TS.SpaceTac.UI { this.sheet = sheet; - let sloticon = new Phaser.Button(this.game, 150, 150, `character-slot-${SlotType[slot].toLowerCase()}`); + let sloticon = new Phaser.Button(this.game, 150, 150, `character-slots`); + sloticon.frame = slot; sloticon.anchor.set(0.5, 0.5); this.addChild(sloticon); sheet.view.tooltip.bindStaticText(sloticon, `${SlotType[slot]} slot`);