Skip to content

Commit

Permalink
[#4929, #4931] Fix mountable data models, add cover to feat sheet
Browse files Browse the repository at this point in the history
- Move `cover` from `MountableTemplate` to `FeatData` since feats
  are the only item type that display this data on vehicles
- Add "Vehicle Feature" type for features and display a cover
  field if this type is selected
- Remove `armor` from `MountableTemplate` and define directly on
  `WeaponData`, since `EquipmentData` already has armor
- Move to using localization prefixes for mountable labels
- Change cover labels shown on vehicle sheet to remove distinction
  between `0` and `null` values

Closes #4929
Closes #4931
  • Loading branch information
arbron committed Jan 13, 2025
1 parent 58df745 commit 9486d21
Show file tree
Hide file tree
Showing 10 changed files with 93 additions and 37 deletions.
48 changes: 46 additions & 2 deletions lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -2021,6 +2021,10 @@

"DND5E.FEATURE": {
"FIELDS": {
"cover": {
"label": "Cover",
"hint": "Cover provided to crew by this vehicle feature."
},
"properties": {
"label": "Feature Properties"
},
Expand Down Expand Up @@ -2069,6 +2073,9 @@
"Blessing": "Blessing",
"Charm": "Charm",
"EpicBoon": "Epic Boon"
},
"Vehicle": {
"Label": "Vehicle Feature"
}
},
"DND5E.Focus": {
Expand Down Expand Up @@ -2302,7 +2309,6 @@
"DND5E.HitPointsTempMaxHint": "Temporary change to the maximum HP.",
"DND5E.HitPointsTempMaxShort": "Temp Max HP",
"DND5E.HP": "HP",
"DND5E.HealthConditions": "Health Conditions",
"DND5E.HPFormula": "Health Formula",
"DND5E.HPFormulaError": "The provided hit point formula could not be evaluated.",
"DND5E.HPFormulaRollMessage": "Roll Hit Point Formula",
Expand Down Expand Up @@ -3060,7 +3066,6 @@
"Name": "Species Name"
},
"DND5E.Speed": "Speed",
"DND5E.SpeedConditions": "Speed Conditions",
"DND5E.SpeedSpecial": "Special Movement",
"DND5E.SpellAbility": "Spellcasting Ability",
"DND5E.SpellAbilitySet": "Set as Primary Spellcasting Ability",
Expand Down Expand Up @@ -3945,6 +3950,40 @@
},

"DND5E.Value": "Value",

"DND5E.VEHICLE": {
"MOUNTABLE": {
"FIELDS": {
"crewed": {
"label": "Crewed"
},
"hp": {
"label": "Hit Points",
"conditions": {
"label": "Health Conditions"
},
"dt": {
"label": "Damage Threshold"
},
"max": {
"label": "Max HP"
},
"value": {
"label": "Current HP"
}
},
"speed": {
"conditions": {
"label": "Speed Conditions"
},
"value": {
"label": "Speed"
}
}
}
}
},

"DND5E.Vehicle": "Vehicle",
"DND5E.VehicleActions": "Actions",
"DND5E.VehicleActionsHint": "Actions taken with full crew complement",
Expand Down Expand Up @@ -3990,6 +4029,11 @@
"label": "Ammunition Type"
}
},
"armor": {
"value": {
"label": "Armor Class"
}
},
"damage": {
"hint": "Intrinsic damage dice from the weapon. Ability modifier and additional damage parts will be provided automatically when attacking."
},
Expand Down
10 changes: 5 additions & 5 deletions module/applications/actor/vehicle-sheet.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,16 @@ export default class ActorSheet5eVehicle extends ActorSheet5e {
context.toggleTitle = game.i18n.localize(`DND5E.${isCrewed ? "Crewed" : "Uncrewed"}`);

// Handle crew actions
if ( item.type === "feat" && item.system.activation.type === "crew" ) {
context.cover = game.i18n.localize(`DND5E.${item.system.cover ? "CoverTotal" : "None"}`);
if ( item.system.cover === .5 ) context.cover = "½";
if ( (item.type === "feat") && (item.system.activation.type === "crew") ) {
if ( item.system.cover === 1 ) context.cover = game.i18n.localize("DND5E.CoverTotal");
else if ( item.system.cover === .5 ) context.cover = "½";
else if ( item.system.cover === .75 ) context.cover = "¾";
else if ( item.system.cover === null ) context.cover = "—";
else context.cover = "—";
}

// Prepare vehicle weapons
if ( (item.type === "equipment") || (item.type === "weapon") ) {
context.threshold = item.system.hp.dt ? item.system.hp.dt : "—";
context.threshold = item.system.hp?.dt ? item.system.hp.dt : "—";
}
}

Expand Down
3 changes: 3 additions & 0 deletions module/config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1884,6 +1884,9 @@ DND5E.featureTypes = {
charm: "DND5E.Feature.SupernaturalGift.Charm",
epicBoon: "DND5E.Feature.SupernaturalGift.EpicBoon"
}
},
vehicle: {
label: "DND5E.Feature.Vehicle.Label"
}
};
preLocalize("featureTypes", { key: "label" });
Expand Down
2 changes: 1 addition & 1 deletion module/data/item/equipment.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export default class EquipmentData extends ItemDataModel.mixin(
/* -------------------------------------------- */

/** @override */
static LOCALIZATION_PREFIXES = ["DND5E.SOURCE"];
static LOCALIZATION_PREFIXES = ["DND5E.MOUNTABLE", "DND5E.SOURCE"];

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

Expand Down
7 changes: 6 additions & 1 deletion module/data/item/feat.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ const { ArrayField, BooleanField, NumberField, SchemaField, SetField, StringFiel
* @mixes ItemDescriptionTemplate
* @mixes ItemTypeTemplate
*
* @property {Advancement[]} Advancement objects for this feature.
* @property {Advancement[]} advancement Advancement objects for this feature.
* @property {number} cover Amount of cover this feature affords to its crew on a vehicle.
* @property {boolean} crewed Is this vehicle feature currently crewed?
* @property {object} enchant
* @property {string} enchant.max Maximum number of items that can have this enchantment.
* @property {string} enchant.period Frequency at which the enchantment can be swapped.
Expand All @@ -41,6 +43,8 @@ export default class FeatData extends ItemDataModel.mixin(
static defineSchema() {
return this.mergeSchema(super.defineSchema(), {
advancement: new ArrayField(new AdvancementField(), { label: "DND5E.AdvancementTitle" }),
cover: new NumberField({ min: 0, max: 1 }),
crewed: new BooleanField(),
enchant: new SchemaField({
max: new FormulaField({ deterministic: true }),
period: new StringField()
Expand Down Expand Up @@ -164,6 +168,7 @@ export default class FeatData extends ItemDataModel.mixin(
placeholder: "DND5E.Requirements" }
];
context.parts = ["dnd5e.details-feat", "dnd5e.field-uses"];
context.coverOptions = Object.entries(CONFIG.DND5E.cover).map(([value, label]) => ({ value, label }));
}

/* -------------------------------------------- */
Expand Down
41 changes: 17 additions & 24 deletions module/data/item/templates/mountable.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,33 @@ const { BooleanField, NumberField, SchemaField, StringField } = foundry.data.fie
/**
* Data model template for equipment that can be mounted on a vehicle.
*
* @property {object} armor Equipment's armor class.
* @property {number} armor.value Armor class value for equipment.
* @property {number} cover Amount of cover does this item affords to its crew on a vehicle.
* @property {boolean} crewed Is this equipment currently crewed?
* @property {object} hp Equipment's hit points.
* @property {number} hp.value Current hit point value.
* @property {number} hp.max Max hit points.
* @property {number} hp.dt Damage threshold.
* @property {string} hp.conditions Conditions that are triggered when this equipment takes damage.
* @property {object} speed Speed granted by a piece of vehicle equipment.
* @property {boolean} crewed Is this equipment currently crewed?
* @property {object} hp
* @property {number} hp.value Current hit point value.
* @property {number} hp.max Max hit points.
* @property {number} hp.dt Damage threshold.
* @property {string} hp.conditions Conditions that are triggered when this equipment takes damage.
* @property {object} speed
* @property {string} speed.conditions Conditions that may affect item's speed.
* @property {number} speed.value Speed granted by this piece of equipment measured in feet or meters
* depending on system setting.
* @property {string} speed.conditions Conditions that may affect item's speed.
* @mixin
*/
export default class MountableTemplate extends SystemDataModel {
/** @inheritDoc */
static defineSchema() {
return {
armor: new SchemaField({
value: new NumberField({ required: true, integer: true, min: 0, label: "DND5E.ArmorClass" })
}, {label: "DND5E.ArmorClass"}),
cover: new NumberField({ min: 0, max: 1, label: "DND5E.Cover" }),
crewed: new BooleanField({ label: "DND5E.Crewed" }),
crewed: new BooleanField(),
hp: new SchemaField({
value: new NumberField({ required: true, integer: true, min: 0, label: "DND5E.HitPointsCurrent" }),
max: new NumberField({ required: true, integer: true, min: 0, label: "DND5E.HitPointsMax" }),
dt: new NumberField({ required: true, integer: true, min: 0, label: "DND5E.DamageThreshold" }),
conditions: new StringField({required: true, label: "DND5E.HealthConditions"})
}, {label: "DND5E.HitPoints"}),
conditions: new StringField(),
dt: new NumberField({ integer: true, min: 0 }),
max: new NumberField({ integer: true, min: 0 }),
value: new NumberField({ integer: true, min: 0 })
}, { required: false, initial: undefined }),
speed: new SchemaField({
value: new NumberField({required: true, min: 0, label: "DND5E.Speed"}),
conditions: new StringField({required: true, label: "DND5E.SpeedConditions"})
}, {required: false, initial: undefined, label: "DND5E.Speed"})
conditions: new StringField(),
value: new NumberField({ min: 0 })
}, { required: false, initial: undefined })
};
}
}
7 changes: 6 additions & 1 deletion module/data/item/weapon.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ const { NumberField, SchemaField, SetField, StringField } = foundry.data.fields;
*
* @property {object} ammunition
* @property {string} ammunition.type Type of ammunition fired by this weapon.
* @property {object} armor
* @property {number} armor.value Siege or vehicle weapon's armor class.
* @property {object} damage
* @property {DamageData} damage.base Weapon's base damage.
* @property {DamageData} damage.versatile Weapon's versatile damage.
Expand All @@ -48,7 +50,7 @@ export default class WeaponData extends ItemDataModel.mixin(
/* -------------------------------------------- */

/** @override */
static LOCALIZATION_PREFIXES = ["DND5E.WEAPON", "DND5E.RANGE", "DND5E.SOURCE"];
static LOCALIZATION_PREFIXES = ["DND5E.WEAPON", "DND5E.MOUNTABLE", "DND5E.RANGE", "DND5E.SOURCE"];

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

Expand All @@ -59,6 +61,9 @@ export default class WeaponData extends ItemDataModel.mixin(
ammunition: new SchemaField({
type: new StringField()
}),
armor: new SchemaField({
value: new NumberField({ integer: true, min: 0 })
}),
damage: new SchemaField({
base: new DamageField(),
versatile: new DamageField()
Expand Down
4 changes: 4 additions & 0 deletions templates/items/details/details-feat.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
label=(localize "DND5E.ItemFeatureSubtype" category=(lookup (lookup config.featureTypes source.type.value) "label")) }}
{{/if}}

{{#if (eq system.type.value "vehicle")}}
{{ formField fields.cover value=source.cover options=coverOptions }}
{{/if}}

{{!-- Feature Prerequisites --}}
{{ formField fields.prerequisites.fields.level value=source.prerequisites.level }}
{{ formField fields.prerequisites.fields.repeatable value=source.prerequisites.repeatable
Expand Down
6 changes: 4 additions & 2 deletions templates/items/details/details-mountable.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@

{{!-- Conditions --}}
{{ formInput fields.hp.fields.conditions value=source.hp.conditions input=inputs.createTextInput
placeholder=(localize "DND5E.HealthConditions") localize=true classes="full-width" }}
placeholder=(localize "DND5E.VEHICLE.MOUNTABLE.FIELDS.hp.conditions.label") localize=true
classes="full-width" }}
</div>

{{!-- Speed --}}
Expand All @@ -43,7 +44,8 @@

{{!-- Conditions --}}
{{ formInput fields.speed.fields.conditions value=source.speed.conditions input=inputs.createTextInput
placeholder=(localize "DND5E.SpeedConditions") localize=true classes="full-width" }}
placeholder=(localize "DND5E.VEHICLE.MOUNTABLE.FIELDS.speed.conditions.label") localize=true
classes="full-width" }}
</div>
{{/if}}
</fieldset>
2 changes: 1 addition & 1 deletion templates/items/parts/item-mountable.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
</div>

<div class="form-group">
<label>{{localize 'DND5E.HealthConditions'}}</label>
<label>{{localize 'DND5E.VEHICLE.MOUNTABLE.FIELDS.hp.conditions.label'}}</label>
<div class="form-fields">
<input type="text" name="system.hp.conditions" value="{{system.hp.conditions}}">
</div>
Expand Down

0 comments on commit 9486d21

Please sign in to comment.