diff --git a/modules/item/item-wfrp4e.js b/modules/item/item-wfrp4e.js index 0ddf3918d..51b7dca56 100644 --- a/modules/item/item-wfrp4e.js +++ b/modules/item/item-wfrp4e.js @@ -1187,25 +1187,13 @@ export default class ItemWfrp4e extends Item { return value // If range modification was handwritten, process it - if (ammoValue.toLowerCase() == game.i18n.localize("as weapon")) { } - else if (ammoValue.toLowerCase() == "as weapon") { } - // Do nothing to weapon's range - else if (ammoValue.toLowerCase() == game.i18n.localize("half weapon")) - value /= 2; - else if (ammoValue.toLowerCase() == "half weapon") - value /= 2; - else if (ammoValue.toLowerCase() == game.i18n.localize("third weapon")) - value /= 3; - else if (ammoValue.toLowerCase() == "third weapon") - value /= 3; - else if (ammoValue.toLowerCase() == game.i18n.localize("quarter weapon")) - value /= 4; - else if (ammoValue.toLowerCase() == "quarter weapon") - value /= 4; - else if (ammoValue.toLowerCase() == game.i18n.localize("twice weapon")) - value *= 2; - else if (ammoValue.toLowerCase() == "twice weapon") - value *= 2; + if (ammoValue.toLowerCase() === game.i18n.localize("as weapon") || ammoValue.toLowerCase() === "as weapon") + return value; + + // Check for generic word modifiers such as "half", "triple" etc. + let modifier = WFRP_Utility.processWordedModifier(ammoValue, value); + if (modifier !== false) + return modifier; else // If the range modification is a formula (supports +X -X /X *X) { try // Works for + and - @@ -1218,6 +1206,7 @@ export default class ItemWfrp4e extends Item { value = Math.floor((0, eval)(value + ammoRange)); } } + return value } @@ -1246,9 +1235,18 @@ export default class ItemWfrp4e extends Item { let sortedCharacteristics = Object.entries(this.actor.characteristics).sort((a,b) => -1 * a[1].label.localeCompare(b[1].label)); sortedCharacteristics.forEach(arr => { let ch = arr[0]; - // Handle characteristic with bonus first - formula = formula.replace(game.wfrp4e.config.characteristicsBonus[ch].toLowerCase(), this.actor.characteristics[ch].bonus); - formula = formula.replace(game.wfrp4e.config.characteristics[ch].toLowerCase(), this.actor.characteristics[ch].value); + let chBonusText = game.wfrp4e.config.characteristicsBonus[ch].toLowerCase(); + let chText = game.wfrp4e.config.characteristics[ch].toLowerCase(); + let chBonusValue = this.actor.characteristics[ch].bonus; + let chValue = this.actor.characteristics[ch].value; + + // Handle characteristic with bonus first including worded modifiers (such as Half) + if (formula.includes(chBonusText) || formula.includes(chText)) { + formula = formula.replace(chBonusText, WFRP_Utility.processWordedModifier(formula, chBonusValue, true)); + formula = formula.replace(chText, WFRP_Utility.processWordedModifier(formula, chValue, true)); + // Remove remnants of worded modifiers + formula = WFRP_Utility.removeWordedModifier(formula); + } }); let total = 0; diff --git a/modules/system/utility-wfrp4e.js b/modules/system/utility-wfrp4e.js index b44c0875b..af2e0e437 100644 --- a/modules/system/utility-wfrp4e.js +++ b/modules/system/utility-wfrp4e.js @@ -1396,6 +1396,110 @@ export default class WFRP_Utility { }) } + + /** + * Extracted to separate function to be used by multiple functions + * + * @return {{twice: {words: (*|string)[], value: number}, half: {words: (*|string)[], value: number}, quadruple: {words: (*|string)[], value: number}, third: {words: (*|string)[], value: number}, triple: {words: (*|string)[], value: number}, quarter: {words: (*|string)[], value: number}}} + */ + static _getWordedModifiers() { + return { + quarter: { + value: 1/4, + words: [ + game.i18n.localize("quarter weapon"), + game.i18n.localize("quarter"), + "quarter" + ] + }, + third: { + value: 1/3, + words: + [ + game.i18n.localize("third weapon"), + game.i18n.localize("third"), + "third" + ] + }, + half: { + value: 1/2, + words: [ + game.i18n.localize("half weapon"), + game.i18n.localize("half"), + "half" + ] + }, + twice: { + value: 2.0, + words: [ + game.i18n.localize("twice weapon"), + game.i18n.localize("double"), + "twice", + "double" + ] + }, + triple: { + value: 3.0, + words: [ + game.i18n.localize("triple"), + "triple" + ] + }, + quadruple: { + value: 4.0, + words: [ + game.i18n.localize("quadruple"), + "quadruple" + ] + } + } + } + + /** + * Transforms value by amount described by a worded modifier found in the text + * + * @param {String} text text possibly containing worded modifiers + * @param {Number} value value to be processed + * @param {boolean} returnOriginal whether or not function should return original value if modifier wasn't found. + * + * @return {Number|false} + */ + static processWordedModifier(text, value, returnOriginal = false) { + const modifiers = WFRP_Utility._getWordedModifiers(); + text = text.toLowerCase(); + + for (let modifier of Object.values(modifiers)) { + for (let word of modifier.words) { + if (text.includes(word)) + return value * modifier.value; + } + } + + if (returnOriginal) + return value; + + return false; + } + + /** + * Transforms text and removes any and all found instances of worded modifiers. + * + * @param {String} text + * + * @return {String} + */ + static removeWordedModifier(text) { + const modifiers = WFRP_Utility._getWordedModifiers(); + + for (let modifier of Object.values(modifiers)) { + for (let word of modifier.words) { + if (text.includes(word)) + text = text.replaceAll(word, ''); + } + } + + return text.trim(); + } } diff --git a/static/lang/en.json b/static/lang/en.json index ac6153b40..a0b46b641 100644 --- a/static/lang/en.json +++ b/static/lang/en.json @@ -316,6 +316,13 @@ "third weapon": "third weapon", "quarter weapon": "quarter weapon", "twice weapon": "twice weapon", + "quarter": "quarter", + "third": "third", + "half": "half", + "twice": "twice", + "double": "double", + "triple": "triple", + "quadruple": "quadruple", "Basic" : "Basic", "Advanced" : "Advanced",