diff --git a/CHANGELOG.md b/CHANGELOG.md
index fcc5913e..2b09a37f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,11 +3,12 @@
* Updated "item cards" to match the Mandar theme
* This change includes many minor improvements to the cards, such as showing damage on weapons and purchased talents on specializations
* The action to take when removing a combatant from combat is now configurable. This is in place of the previously-confusing (and quite annoying) behavior where you had to claim a slot in order to remove a combatant
+ * Dragging-and-dropping items on actors now prompts for spending XP to purchase that item ([#1588](https://github.com/StarWarsFoundryVTT/StarWarsFFG/issues/1588))
* Fixes:
* Includes species characteristics bonus when calculating upgrade cost ([#1638](https://github.com/StarWarsFoundryVTT/StarWarsFFG/issues/1638))
* Specializations: Talents are now correctly looked up in compendium
* Removed "unused" slot checking (on combatant defeat) as they would sometimes lead to actors being unable to act
- * Weapon "special" text now properly renders dice icons ([#1625](https://github.com/StarWarsFoundryVTT/StarWarsFFG/issues/1625))
+ * Weapon `special` text now properly renders dice icons ([#1625](https://github.com/StarWarsFoundryVTT/StarWarsFFG/issues/1625))
`1.902`
* Features:
diff --git a/lang/en.json b/lang/en.json
index b0bd69bb..430e39f2 100644
--- a/lang/en.json
+++ b/lang/en.json
@@ -723,5 +723,9 @@
"SWFFG.Settings.Purchase.SignatureAbility.Name": "Signature Abilities Compendiums",
"SWFFG.Settings.Purchase.SignatureAbility.Hint": "Comma seperated compendiums to search for buying Signature Abilities (no spaces)",
"SWFFG.Settings.Purchase.Talent.Name": "Talent Compendiums",
- "SWFFG.Settings.Purchase.Talent.Hint": "Comma seperated compendiums to search for buying Talents (no spaces)"
+ "SWFFG.Settings.Purchase.Talent.Hint": "Comma seperated compendiums to search for buying Talents (no spaces)",
+ "SWFFG.DragDrop.Title": "Purchase item, or grant for 0 xp?",
+ "SWFFG.DragDrop.PurchaseItem": "Purchase",
+ "SWFFG.DragDrop.GrantItem": "Grant",
+ "SWFFG.DragDrop.XPLog": "drag-and-drop"
}
diff --git a/modules/actors/actor-sheet-ffg.js b/modules/actors/actor-sheet-ffg.js
index c5131f7b..c8a572d0 100644
--- a/modules/actors/actor-sheet-ffg.js
+++ b/modules/actors/actor-sheet-ffg.js
@@ -83,6 +83,48 @@ export class ActorSheetFFG extends ActorSheet {
await xpLogEarn(this.actor, startingXP, curAvailable + startingXP, curTotal + startingXP, game.i18n.format("SWFFG.GrantXPSpecies", {species: itemData.name}) );
}
+ if (this.actor.type === "character" && ["talent", "specialization", "signatureability", "forcepower"].includes(itemData.type)) {
+ const cost = await this.calcPurchasePrice(itemData);
+ const availableXP = this.actor.system.experience.available;
+ if (cost > 0 && cost < availableXP) {
+ new Dialog(
+ {
+ title: game.i18n.localize("SWFFG.DragDrop.Title"),
+ buttons: {
+ purchase: {
+ icon: '',
+ label: game.i18n.localize("SWFFG.DragDrop.PurchaseItem"),
+ callback: async (that) => {
+ if (cost > 0) {
+ await this.object.update({
+ system: {
+ experience: {
+ available: availableXP - cost,
+ }
+ }
+ });
+ await xpLogSpend(
+ this.actor, `${game.i18n.localize("SWFFG.DragDrop.XPLog")} ${itemData.type} ${itemData.name}`,
+ cost,
+ this.actor.system.experience.available,
+ this.actor.system.experience.total
+ );
+ }
+ },
+ },
+ grant: {
+ icon: '',
+ label: game.i18n.localize("SWFFG.DragDrop.GrantItem"),
+ },
+ },
+ },
+ {
+ classes: ["dialog", "starwarsffg"],
+ }
+ ).render(true);
+ }
+ }
+
// Create the owned item
return this._onDropItemCreate(itemData);
} else {
@@ -90,6 +132,39 @@ export class ActorSheetFFG extends ActorSheet {
}
}
+ async calcPurchasePrice(itemData) {
+ let cost = 0;
+ if (itemData.type === "specialization") {
+ // check if the specialization is in career
+ const career = this.actor.items.find(i => i.type === "career");
+ if (career) {
+ const inCareerSpecializations = Object.values(career?.system?.specializations) || [];
+ let inCareer = false;
+ for (const careerSpecialization of inCareerSpecializations) {
+ if (careerSpecialization.name === itemData.name) {
+ inCareer = true;
+ break;
+ }
+ }
+ const specializationCount = (this.actor.items.filter(i => i.type === "specialization") || []).length;
+ cost = (specializationCount + 1) * 10;
+ if (!inCareer) {
+ cost += 10;
+ }
+ return cost;
+ } else {
+ return -1;
+ }
+ } else if (itemData.type === "talent") {
+ return -1;
+ } else if (itemData.type === "signatureability") {
+ return itemData.system.base_cost;
+ } else if (itemData.type === "forcepower") {
+ return itemData.system.base_cost;
+ }
+ return -1;
+ }
+
/* -------------------------------------------- */
/** @override */
@@ -1990,7 +2065,7 @@ export class ActorSheetFFG extends ActorSheet {
}
worldItemsPack = sortDataBy(worldItemsPack, "name");
selectableItems.push({pack: game.i18n.localize("SWFFG.Actors.Sheets.Purchase.Talent.WorldItemsGroup"), items: worldItemsPack});
-
+
for (const source of sources) {
const pack = game.packs.get(source);
if (!pack) {
@@ -2080,7 +2155,7 @@ export class ActorSheetFFG extends ActorSheet {
const characteristicCurrentRank = this.actor.system.attributes[characteristic].value;
// this is the value without items that modify it
const characteristicCostValue = ModifierHelpers.getBaseValue(this.actor.items, characteristic, "Characteristic") + characteristicCurrentRank;
-
+
if (characteristicValue >= game.settings.get("starwarsffg", "maxAttribute")) {
ui.notifications.warn(game.i18n.localize("SWFFG.Actors.Sheets.Purchase.Characteristic.Max"));
return;