Skip to content

Commit

Permalink
[#4958] Allow features to be repeatable in item choice
Browse files Browse the repository at this point in the history
Adds "Repeatable" data to the prerequisite data on `feat` items.
Repeatable features can be selected more than once inside an item
choice advancement.

Closes #4958
  • Loading branch information
arbron committed Jan 3, 2025
1 parent 4a941da commit 2013869
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 19 deletions.
20 changes: 20 additions & 0 deletions lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1909,6 +1909,21 @@
"DND5E.FavoriteRemove": "Remove Favorite",
"DND5E.Favorites": "Favorites",
"DND5E.FeatureActionRecharge": "Action Recharge",

"DND5E.FEATURE": {
"FIELDS": {
"properties": {
"label": "Feature Properties"
},
"requirements": {
"label": "Requirements"
},
"type": {
"label": "Feature Type"
}
}
},

"DND5E.Feature": {
"Background": "Background Feature",
"Class": {
Expand Down Expand Up @@ -2509,9 +2524,14 @@
"Header": "Feature Prerequisites",
"FIELDS": {
"prerequisites": {
"label": "Prerequisites",
"level": {
"label": "Required Level",
"hint": "Character or class level required to select this feature when levelling up."
},
"repeatable": {
"hint": "This feature can be chosen more than once.",
"label": "Repeatable"
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,6 @@ export default class AbilityScoreImprovementFlow extends AdvancementFlow {

/** @inheritDoc */
async _updateObject(event, formData) {
// TODO: Pass through retained feat data
await this.advancement.apply(this.level, {
type: this.feat ? "feat" : "asi",
assignments: this.assignments,
Expand Down
15 changes: 9 additions & 6 deletions module/applications/advancement/item-choice-flow.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ export default class ItemChoiceFlow extends ItemGrantFlow {
i.checked = this.selected.has(i.uuid);
i.disabled = !i.checked && context.choices.full;
const validLevel = (i.system.prerequisites?.level ?? -Infinity) <= this.level;
if ( !previouslySelected.has(i.uuid) && validLevel ) items.push(i);
const available = !previouslySelected.has(i.uuid) || i.system.prerequisites?.repeatable;
if ( available && validLevel ) items.push(i);
}
return items;
}, []);
Expand Down Expand Up @@ -197,11 +198,13 @@ export default class ItemChoiceFlow extends ItemGrantFlow {
if ( this.selected.has(item.uuid) ) return false;

// Check to ensure the dropped item hasn't been selected at a lower level
for ( const [level, data] of Object.entries(this.advancement.value.added ?? {}) ) {
if ( level >= this.level ) continue;
if ( Object.values(data).includes(item.uuid) ) {
ui.notifications.error("DND5E.AdvancementItemChoicePreviouslyChosenWarning", {localize: true});
return null;
if ( item.system.prerequisites?.repeatable !== true ) {
for ( const [level, data] of Object.entries(this.advancement.value.added ?? {}) ) {
if ( level >= this.level ) continue;
if ( Object.values(data).includes(item.uuid) ) {
ui.notifications.error("DND5E.AdvancementItemChoicePreviouslyChosenWarning", {localize: true});
return null;
}
}
}

Expand Down
20 changes: 11 additions & 9 deletions module/data/item/feat.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import ItemTypeTemplate from "./templates/item-type.mjs";
import ItemTypeField from "./fields/item-type-field.mjs";
import { FormulaField } from "../fields/_module.mjs";

const { NumberField, SchemaField, SetField, StringField } = foundry.data.fields;
const { BooleanField, NumberField, SchemaField, SetField, StringField } = foundry.data.fields;

/**
* Data definition for Feature items.
Expand All @@ -18,6 +18,7 @@ const { NumberField, SchemaField, SetField, StringField } = foundry.data.fields;
* @property {string} enchant.period Frequency at which the enchantment can be swapped.
* @property {object} prerequisites
* @property {number} prerequisites.level Character or class level required to choose this feature.
* @property {boolean} prerequisites.repeatable Can this item be selected more than once?
* @property {Set<string>} properties General properties of a feature item.
* @property {string} requirements Actor details required to use this feature.
*/
Expand All @@ -30,25 +31,24 @@ export default class FeatData extends ItemDataModel.mixin(
/* -------------------------------------------- */

/** @override */
static LOCALIZATION_PREFIXES = ["DND5E.ENCHANTMENT", "DND5E.Prerequisites", "DND5E.SOURCE"];
static LOCALIZATION_PREFIXES = ["DND5E.FEATURE", "DND5E.ENCHANTMENT", "DND5E.Prerequisites", "DND5E.SOURCE"];

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

/** @inheritDoc */
static defineSchema() {
return this.mergeSchema(super.defineSchema(), {
enchant: new SchemaField({
max: new FormulaField({deterministic: true}),
max: new FormulaField({ deterministic: true }),
period: new StringField()
}),
type: new ItemTypeField({baseItem: false}, {label: "DND5E.ItemFeatureType"}),
prerequisites: new SchemaField({
level: new NumberField({integer: true, min: 0})
level: new NumberField({ integer: true, min: 0 }),
repeatable: new BooleanField()
}),
properties: new SetField(new StringField(), {
label: "DND5E.ItemFeatureProperties"
}),
requirements: new StringField({required: true, nullable: true, label: "DND5E.Requirements"})
properties: new SetField(new StringField()),
requirements: new StringField({ required: true, nullable: true }),
type: new ItemTypeField({ baseItem: false })
});
}

Expand Down Expand Up @@ -161,6 +161,8 @@ export default class FeatData extends ItemDataModel.mixin(
placeholder: "DND5E.Requirements" }
];
context.parts = ["dnd5e.details-feat", "dnd5e.field-uses"];
context.showAbilityScoreIncrease = this.type.value === "feat";
context.abilityOptions = Object.entries(CONFIG.DND5E.abilities).map(([value, { label }]) => ({ value, label }));
}

/* -------------------------------------------- */
Expand Down
6 changes: 3 additions & 3 deletions templates/items/details/details-feat.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
{{/if}}

{{!-- Feature Prerequisites --}}
{{ formField fields.prerequisites.fields.level value=source.prerequisites.level localize=true step=1
label="DND5E.Prerequisites.FIELDS.prerequisites.level.label"
hint="DND5E.Prerequisites.FIELDS.prerequisites.level.hint" }}
{{ formField fields.prerequisites.fields.level value=source.prerequisites.level }}
{{ formField fields.prerequisites.fields.repeatable value=source.prerequisites.repeatable
input=inputs.createCheckboxInput }}

{{!-- Feature Properties --}}
{{ formField fields.properties options=properties.options label="DND5E.ItemFeatureProperties" localize=true
Expand Down

0 comments on commit 2013869

Please sign in to comment.