diff --git a/src/lang/en.json b/src/lang/en.json index 584e80d5..d263e434 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -727,6 +727,7 @@ "DL.WealthLifestyle": "Lifestyle: ", "DL.WealthTitle": "Wealth", "DL.WeaponAdd": "Add weapon", + "DL.WeaponAmmoRequired": "Ammunition required", "DL.WeaponAttack20": "Extra Damage 20+", "DL.WeaponAttack20Text": "Attack Roll 20+", "DL.WeaponAttackModifier": "Attack Modifier", @@ -744,6 +745,9 @@ "DL.WeaponModifiers": "Modifiers", "DL.WeaponName": "Weapon name", "DL.WeaponProperties": "Properties", + "DL.WeaponResourceComsumption": "Resource consumption", + "DL.WeaponRunOutOfAmmo": "{weaponName} has run out of its ammunition.", + "DL.WeaponNoAmmo": "{weaponName} has no assigned ammunition.", "DL.WeaponTitle": "Weapons", "DL.WeaponWear": "Equip weapon", "DL.With": "with" diff --git a/src/module/actor/actor.js b/src/module/actor/actor.js index 06a3bf1a..2f1407ab 100644 --- a/src/module/actor/actor.js +++ b/src/module/actor/actor.js @@ -417,6 +417,27 @@ export class DemonlordActor extends Actor { */ async rollWeaponAttack(itemID, _options = {event: null}) { const item = this.getEmbeddedDocument('Item', itemID) + let ammoItem + + // Check if there is an ammo for weapon + if (item.system.consume.ammorequired) { + ammoItem = await this.ammo.find(x => x.id === item.system.consume.ammoitemid) + if (ammoItem) { + if (ammoItem.system.quantity === 0) { + return ui.notifications.warn( + game.i18n.format('DL.WeaponRunOutOfAmmo', { + weaponName: item.name, + }), + ) + } + } else { + return ui.notifications.warn( + game.i18n.format('DL.WeaponNoAmmo', { + weaponName: item.name, + }), + ) + } + } // If no attribute to roll, roll without modifiers and boons const attribute = item.system.action?.attack @@ -427,11 +448,16 @@ export class DemonlordActor extends Actor { // Check if actor is blocked by an affliction if (!DLAfflictions.isActorBlocked(this, 'action', attribute)) - launchRollDialog(game.i18n.localize('DL.DialogAttackRoll') + game.i18n.localize(item.name), async html => - await this.rollAttack(item, html.find('[id="boonsbanes"]').val(), html.find('[id="modifier"]').val()), - ) + launchRollDialog(game.i18n.localize('DL.DialogAttackRoll') + game.i18n.localize(item.name), async html => { + await this.rollAttack(item, html.find('[id="boonsbanes"]').val(), html.find('[id="modifier"]').val()) + // Decrease ammo quantity + if (item.system.consume.ammorequired) { + await ammoItem.update({ + 'system.quantity': ammoItem.system.quantity - item.system.consume.amount, + }) + } + }) } - /* -------------------------------------------- */ async rollAttribute(attribute, inputBoons, inputModifier) { diff --git a/src/module/data/item/WeaponDataModel.js b/src/module/data/item/WeaponDataModel.js index a64eefff..28291058 100644 --- a/src/module/data/item/WeaponDataModel.js +++ b/src/module/data/item/WeaponDataModel.js @@ -17,7 +17,12 @@ export default class WeaponDataModel extends foundry.abstract.DataModel { wear: makeBoolField(true), quantity: makeIntField(1), availability: makeStringField(), - value: makeStringField() + value: makeStringField(), + consume: new foundry.data.fields.SchemaField({ + ammorequired: makeBoolField(false), + amount: makeIntField(1), + ammoitemid: makeStringField() + }), } } } @@ -37,6 +42,11 @@ export function makeWeaponSchema() { wear: makeBoolField(true), quantity: makeIntField(1), availability: makeStringField(), - value: makeStringField() + value: makeStringField(), + consume: new foundry.data.fields.SchemaField({ + ammorequired: makeBoolField(false), + amount: makeIntField(1), + ammoitemid: makeStringField() + }), }) } \ No newline at end of file diff --git a/src/module/item/sheets/base-item-sheet.js b/src/module/item/sheets/base-item-sheet.js index 8172c6b7..6a504279 100644 --- a/src/module/item/sheets/base-item-sheet.js +++ b/src/module/item/sheets/base-item-sheet.js @@ -164,7 +164,7 @@ export default class DLBaseItemSheet extends ItemSheet { }) tippy('.dl-new-project-2.dropdown', { content(reference) { - html = buildDropdownList(reference.attributes.name.value, reference.attributes.value.value) + html = buildDropdownList(reference.attributes.name.value, reference.attributes.value.value, data) return html }, allowHTML: true, @@ -190,6 +190,14 @@ export default class DLBaseItemSheet extends ItemSheet { inputs.focus(ev => ev.currentTarget.select()) } + // Weapon ammo required checkbox + html.find('.dl-ammorequired').click(async _ => { + await this.document.update({ + 'system.consume.ammorequired': !this.document.system.consume.ammorequired, + 'system.consume.ammoitemid' : '' + }) + }) + // Item autoDestroy checkbox html.find('.dl-autodestroy').click(async _ => { await this.document.update({'system.autoDestroy': !this.document.system.autoDestroy}) diff --git a/src/module/utils/handlebars-helpers.js b/src/module/utils/handlebars-helpers.js index 3079c0db..8d989e3a 100644 --- a/src/module/utils/handlebars-helpers.js +++ b/src/module/utils/handlebars-helpers.js @@ -1,3 +1,4 @@ +/* global fromUuidSync */ import {capitalize, enrichHTMLUnrolled, i18n} from "./utils"; import {handlebarsBuildEditor} from "./editor"; @@ -50,7 +51,9 @@ export function registerHandlebarsHelpers() { ) Handlebars.registerHelper('dlAvailabilityDropdown', (groupName, checkedKey) => _buildAvailabilityDropdownItem(groupName, checkedKey)) Handlebars.registerHelper('dlConsumableDropdown', (groupName, checkedKey) => _buildConsumableDropdownItem(groupName, checkedKey)) - Handlebars.registerHelper('dlCheckCharacteristicsIsNull', (actorData) => _CheckCharacteristicsIsNull(actorData)); + Handlebars.registerHelper('dlAmmoDropdown', (groupName, checkedKey, weapon) => _buildAmmoDropdownItem(groupName, checkedKey, weapon)) + Handlebars.registerHelper('dlCheckItemOnActor', (data) => _CheckItemOnActor(data)) + Handlebars.registerHelper('dlCheckCharacteristicsIsNull', (actorData) => _CheckCharacteristicsIsNull(actorData)) } // ---------------------------------------------------- @@ -69,10 +72,9 @@ function _getAttributes(groupName) { attributes = ['', 'C', 'U', 'R', 'E'] } else if (groupName === 'system.requirement.attribute') { attributes = ['', 'strength', 'agility', 'intellect', 'will', 'perception'] - } - else if (groupName === 'system.consumabletype') { + } else if (groupName === 'system.consumabletype') { attributes = ['', 'D', 'F', 'P', 'V', 'T'] - } + } return attributes } @@ -98,11 +100,19 @@ function _buildRadioBoxes(groupName, checkedKey) { // ---------------------------------------------------- function _CheckCharacteristicsIsNull(actorData) { - if (actorData === null) { - return true - } else { - return false - } + if (actorData === null) { + return true + } else { + return false + } +} + +function _CheckItemOnActor(data) { + if (data.indexOf('Actor.') === -1) { + return false + } else { + return true + } } function _buildDropdownItem(groupName, checkedKey) { @@ -174,7 +184,7 @@ function _buildDropdownItemWithValue(groupName, checkedKey, valueName, valueKey) } -export function buildDropdownList(groupName, checkedKey) { +export function buildDropdownList(groupName, checkedKey, data) { let labelPrefix = 'DL.Attribute' let iconPrefix = 'dl-icon-' let useIcon = true @@ -182,6 +192,7 @@ export function buildDropdownList(groupName, checkedKey) { if (groupName === 'path-type') return _buildPathTypeDropdownList(checkedKey) if (groupName === 'level.attributeSelect') return _buildPathAttributeSelectDropdownList(checkedKey) if (groupName.startsWith('level.attributeSelectTwoSet')) return _buildPathAttributeTwoSetDropdownList(groupName, checkedKey) + if (groupName === 'system.consume.ammoitemid') return _buildAmmoDropdownList (groupName, checkedKey, data) if (groupName === 'system.hands') {labelPrefix = 'DL.WeaponHands'; useIcon = false} if (groupName === 'system.consumabletype') {labelPrefix = 'DL.ConsumableType'; useIcon = false} if (groupName === 'system.availability') {labelPrefix = 'DL.Availability', iconPrefix = 'dl-icon-availability-'} @@ -336,6 +347,28 @@ function _buildPathAttributeTwoSetViewSelector(attributeName, isSelected, select return new Handlebars.SafeString(html) } +function _buildAmmoDropdownList(groupName, checkedKey, data) { + let attributes = [{ id: '', name: i18n('DL.None') }] + let html = `