Skip to content

Commit

Permalink
[foundryvtt#1401] Implement ItemChoiceAdvancement for choosing featur…
Browse files Browse the repository at this point in the history
…es & spells
  • Loading branch information
arbron committed Jan 3, 2023
1 parent 70d72c8 commit 104a543
Show file tree
Hide file tree
Showing 21 changed files with 631 additions and 36 deletions.
32 changes: 24 additions & 8 deletions dnd5e.css
Original file line number Diff line number Diff line change
Expand Up @@ -1354,6 +1354,9 @@ h5 {
/* Two Column Configurations */
/* ----------------------------------------- */
/* ----------------------------------------- */
/* Item Choice */
/* ----------------------------------------- */
/* ----------------------------------------- */
/* Scale Value */
/* ----------------------------------------- */
}
Expand Down Expand Up @@ -1402,19 +1405,28 @@ h5 {
.dnd5e.advancement.two-column form .right-column {
grid-area: right;
}
.dnd5e.advancement.two-column form .right-column.level-list label {
flex: 0.5;
padding-right: 0.5rem;
text-align: end;
}
.dnd5e.advancement.two-column form .right-column.level-list :is(input[type="text"], input[type="number"])::placeholder {
opacity: 0.5;
}
.dnd5e.advancement.two-column form button[type="submit"] {
grid-column-end: span 2;
}
.dnd5e.advancement.scale-value {
--grid-two-column-right-size: 0.6fr;
.dnd5e.advancement.item-choice {
--grid-two-column-right-size: 0.5fr;
}
.dnd5e.advancement.scale-value .right-column label {
flex: 0.5;
padding-right: 0.5rem;
text-align: right;
.dnd5e.advancement.item-choice .level-list .hint {
text-align: end;
}
.dnd5e.advancement.scale-value :is(input[type="text"], input[type="number"])::placeholder {
opacity: 0.5;
.dnd5e.advancement.item-choice textarea {
margin-inline-start: 9px;
}
.dnd5e.advancement.scale-value {
--grid-two-column-right-size: 0.6fr;
}
.dnd5e.advancement.scale-value select.new-scale-value {
font-weight: bold;
Expand Down Expand Up @@ -1483,6 +1495,10 @@ h5 {
height: calc(var(--form-field-height) + 5px);
line-height: 1.5em;
}
.dnd5e.advancement.flow form[data-type="ItemChoice"] .item-name .item-delete {
flex: 0 0 20px;
margin-inline-end: 1px;
}
.dnd5e.advancement.flow input.error {
outline: 2px solid red;
}
Expand Down
1 change: 1 addition & 0 deletions icons/LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ SVG Icons from Game-Icons.net
The dnd5e system for Foundry Virtual Tabletop includes icon artwork licensed from Game-icons.net under the Creative Commons license. These icons are packaged with and provided for use in the dnd5e system under their respective licenses, as noted below.

/svg/hit-points.svg - "Heart plus" by Zeromancer under CC0 PDD
/svg/item-choice.svg - "Choice" by Delapouite under CC BY 3.0
/svg/item-grant.svg - "White book" by Willdabeast under CC BY 3.0
/svg/scale-value.svg - "Dice target" by Delapouite under CC BY 3.0
1 change: 1 addition & 0 deletions icons/svg/item-choice.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@
"DND5E.AdvancementConfigurationModeDisabled": "Configuration Disabled",
"DND5E.AdvancementConfigurationModeEnabled": "Configuration Enabled",
"DND5E.AdvancementConfigureTitle": "Configure {item} Advancement",
"DND5E.AdvancementConfigureAllowDrops": "Allow Drops",
"DND5E.AdvancementConfigureAllowDropsHint": "Should players be able to drop their own choices into this advancement?",
"DND5E.AdvancementConfigureDropAreaHint": "Drop Items here to add them to the pool from which a player can choose.",
"DND5E.AdvancementConfiguredComplete": "Fully Configured",
"DND5E.AdvancementConfiguredIncomplete": "Not Configured",
"DND5E.AdvancementControlCreate": "Create Advancement",
Expand All @@ -123,6 +126,8 @@
"DND5E.AdvancementDeleteConfirmationLabel": "Remove advancement changes",
"DND5E.AdvancementDeleteConfirmationMessage": "Deleting this item will also delete all advancement choices made for it. These changes will be removed from your character as long as the checkbox below is checked.",
"DND5E.AdvancementDeleteConfirmationTitle": "Confirm Deletion",
"DND5E.AdvancementFlowDropAreaHint": "Drop an Item here to choose it.",
"DND5E.AdvancementHint": "Hint",
"DND5E.AdvancementHitPointsTitle": "Hit Points",
"DND5E.AdvancementHitPointsHint": "Track the player's hit points for each level in the class.",
"DND5E.AdvancementHitPointsAverage": "Take Average",
Expand All @@ -131,6 +136,18 @@
"DND5E.AdvancementHitPointsMaxAtFirstLevel": "Max at 1st Level: <strong>{max}</strong>",
"DND5E.AdvancementHitPointsRollMessage": "Roll {class} Hit Points",
"DND5E.AdvancementHitPointsRollButton": "Roll {die}",
"DND5E.AdvancementItemChoiceTitle": "Choose Items",
"DND5E.AdvancementItemChoiceHint": "Present the player with a choice of items (such as equipment, features, or spells) that they can choose for their character at one or more levels.",
"DND5E.AdvancementItemChoiceChosen": "Chosen: {current} of {max}",
"DND5E.AdvancementItemChoiceLevelsHint": "Specify how many choices are allowed at each level.",
"DND5E.AdvancementItemChoiceSpellLevelAvailable": "Any Available Level",
"DND5E.AdvancementItemChoiceSpellLevelAvailableWarning": "Only {level} or lower spells can be chosen for this advancement.",
"DND5E.AdvancementItemChoiceSpellLevelSpecificWarning": "Only {level} spells can be chosen for this advancement.",
"DND5E.AdvancementItemChoiceSpellLevelHint": "Only allow choices from spells of this level.",
"DND5E.AdvancementItemChoiceType": "Item Type",
"DND5E.AdvancementItemChoiceTypeHint": "Restrict what Item types can be choosen.",
"DND5E.AdvancementItemChoiceTypeAny": "Anything",
"DND5E.AdvancementItemChoiceTypeWarning": "Only {type} items can be selected for this choice.",
"DND5E.AdvancementItemGrantTitle": "Grant Items",
"DND5E.AdvancementItemGrantHint": "Grant the character items (such as equipment, features, or spells) when they reach a certain level.",
"DND5E.AdvancementItemGrantDropHint": "Drop Items here to add them to the list granted by this advancement.",
Expand Down
42 changes: 33 additions & 9 deletions less/advancement.less
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,17 @@
}
.right-column {
grid-area: right;

&.level-list {
label {
flex: 0.5;
padding-right: 0.5rem;
text-align: end;
}
:is(input[type="text"], input[type="number"])::placeholder {
opacity: 0.5;
}
}
}
button[type="submit"] {
grid-column-end: span 2;
Expand All @@ -60,19 +71,25 @@
}

/* ----------------------------------------- */
/* Scale Value */
/* Item Choice */
/* ----------------------------------------- */
&.scale-value {
--grid-two-column-right-size: 0.6fr;
&.item-choice {
--grid-two-column-right-size: 0.5fr;

.right-column label {
flex: 0.5;
padding-right: 0.5rem;
text-align: right;
.level-list .hint {
text-align: end;
}
:is(input[type="text"], input[type="number"])::placeholder {
opacity: 0.5;

textarea {
margin-inline-start: 9px;
}
}

/* ----------------------------------------- */
/* Scale Value */
/* ----------------------------------------- */
&.scale-value {
--grid-two-column-right-size: 0.6fr;

select {
&.new-scale-value {
Expand Down Expand Up @@ -154,6 +171,13 @@
}
}

form[data-type="ItemChoice"] {
.item-name .item-delete {
flex: 0 0 20px;
margin-inline-end: 1px;
}
}

input.error {
outline: 2px solid red;
}
Expand Down
2 changes: 2 additions & 0 deletions module/applications/advancement/_module.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ export {default as AdvancementSelection} from "./advancement-selection.mjs";

export {default as HitPointsConfig} from "./hit-points-config.mjs";
export {default as HitPointsFlow} from "./hit-points-flow.mjs";
export {default as ItemChoiceConfig} from "./item-choice-config.mjs";
export {default as ItemChoiceFlow} from "./item-choice-flow.mjs";
export {default as ItemGrantConfig} from "./item-grant-config.mjs";
export {default as ItemGrantFlow} from "./item-grant-flow.mjs";
export {default as ScaleValueConfig} from "./scale-value-config.mjs";
Expand Down
4 changes: 2 additions & 2 deletions module/applications/advancement/advancement-config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export default class AdvancementConfig extends FormApplication {
* @param {object} configuration Configuration object.
* @returns {object} Modified configuration.
*/
prepareConfigurationUpdate(configuration) {
async prepareConfigurationUpdate(configuration) {
return configuration;
}

Expand Down Expand Up @@ -148,7 +148,7 @@ export default class AdvancementConfig extends FormApplication {
delete updates.data;
updates = { ...updates, ...data };
}
if ( updates.configuration ) updates.configuration = this.prepareConfigurationUpdate(updates.configuration);
if ( updates.configuration ) updates.configuration = await this.prepareConfigurationUpdate(updates.configuration);
await this.advancement.update(updates);
}

Expand Down
58 changes: 58 additions & 0 deletions module/applications/advancement/item-choice-config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import AdvancementConfig from "./advancement-config.mjs";

/**
* Configuration application for item choices.
*/
export default class ItemChoiceConfig extends AdvancementConfig {

/** @inheritdoc */
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["dnd5e", "advancement", "item-choice", "two-column"],
dragDrop: [{ dropSelector: ".drop-target" }],
dropKeyPath: "pool",
template: "systems/dnd5e/templates/advancement/item-choice-config.hbs",
width: 540
});
}

/* -------------------------------------------- */

/** @inheritdoc */
getData(options={}) {
return {
...super.getData(options),
showSpellConfig: this.advancement.configuration.type === "spell",
validTypes: this.advancement.constructor.VALID_TYPES.reduce((obj, type) => {
obj[type] = game.i18n.localize(`ITEM.Type${type.capitalize()}`);
return obj;
}, {})
};
}

/* -------------------------------------------- */

/** @inheritdoc */
async prepareConfigurationUpdate(configuration) {
if ( configuration.choices ) configuration.choices = this.constructor._cleanedObject(configuration.choices);

// Ensure items are still valid if type restriction or spell restriction are changed
configuration.pool ??= this.advancement.configuration.pool;
configuration.pool = await configuration.pool.reduce(async (pool, uuid) => {
const item = await fromUuid(uuid);
if ( this.advancement._validateItemType(item, {
restriction: configuration.type, spellLevel: configuration.spellLevel ?? false, error: false
}) ) return [...await pool, uuid];
return pool;
}, []);

return configuration;
}

/* -------------------------------------------- */

/** @inheritdoc */
_validateDroppedItem(event, item) {
this.advancement._validateItemType(item);
}
}
Loading

0 comments on commit 104a543

Please sign in to comment.