Skip to content

Commit

Permalink
Merge pull request #17 from dmrickey/mythic_weapon_focus
Browse files Browse the repository at this point in the history
Mythic weapon focus
  • Loading branch information
dmrickey authored Dec 21, 2023
2 parents 5382d33 + 18c1da1 commit d3973b7
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 93 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,13 @@ Automatically add +1 to attack rolls to weapons with `Weapon Focus`. Includes `G
- The dropdown will be added automatically if you add a dictionary flag `greater-weapon-focus` to the feat (or any other Item)
- The choices will be based off of any other `Weapon Focus` feats you already have configured.

### Mythic Weapon Focus
Doubles the bonus from `Weapon Focus` and `Greater Weapon Focus`
- Will automatically include the select input in the feat advanced tab if the feat name includes both `Weapon Focus` and `Mythic`
- This is configurable in the settings to account for different translations
- The dropdown will be added automatically if you add a dictionary flag `mythic-weapon-focus` to the feat (or any other Item)
- The choices will be based off of any other `Weapon Focus` feats you already have configured.

### Racial Weapon Focus
Adds +1 to hit to racial weapons - those weapons must have appropriate racial tags.
- Will Automatically include the select input in the feat advanced tab if the feat is named `Gnome Weapon Focus` (only official racial weapon feat)
Expand Down
8 changes: 7 additions & 1 deletion lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"misfortune": "Misfortune",
"mythicElementalFocus": "Mythic Elemental Focus",
"mythicSpellFocus": "Mythic Spell Focus",
"mythic-weapon-focus": "Mythic Weapon Focus",
"ok": "OK",
"roll-bonuses": "Roll Bonuses",
"school-dc": "Spell School DC",
Expand Down Expand Up @@ -130,6 +131,11 @@
"hint": "The 'Mythic' adjective, feat names are checked for this plus 'Spell Focus'. This is to support translations without having to translate the mod.",
"default": "Mythic"
},
"mythic-weapon-focus": {
"name": "Mythic Weapon Focus",
"hint": "The 'Mythic' adjective, feat names are checked for this plus 'Weapon Focus'. This is to support translations without having to translate the mod.",
"default": "Mythic"
},
"racial-weapon-focus": {
"name": "Racial Weapon Focus",
"hint": "The name of your 'Racial Spell Focus' feat. Only 'Gnome Weapon Focus' officially exists, but this allows for other racial variations. This is to support translations without having to translate the mod.",
Expand Down Expand Up @@ -172,4 +178,4 @@
}
}
}
}
}
2 changes: 2 additions & 0 deletions src/bonuses/weapon-focus/ids.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
export const weaponFocusKey = 'weapon-focus';
export const greaterWeaponFocusKey = 'greater-weapon-focus';
export const mythicWeaponFocusKey = 'mythic-weapon-focus';
export const racialWeaponFocusKey = 'racial-weapon-focus';

export const weaponFocusId = 'n250dFlbykAIAg5Z';
export const greaterWeaponFocusId = 'IER2MzJrjSvxMlNS';
export const mythicWeaponFocusId = 'stJ6Jp1ALN6qgGBr';
export const gnomeWeaponFocusId = '8RzIeYtbx0UtXUge';
103 changes: 73 additions & 30 deletions src/bonuses/weapon-focus/weapon-focus.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,49 @@ import { localHooks } from "../../util/hooks.mjs";
import { registerItemHint } from "../../util/item-hints.mjs";
import { localize } from "../../util/localize.mjs";
import { registerSetting } from "../../util/settings.mjs";
import { signed } from '../../util/to-signed-string.mjs';
import { uniqueArray } from "../../util/unique-array.mjs";
import { gnomeWeaponFocusId, greaterWeaponFocusId, greaterWeaponFocusKey, racialWeaponFocusKey, weaponFocusId, weaponFocusKey } from "./ids.mjs";

const allKeys = [weaponFocusKey, greaterWeaponFocusKey];
import {
gnomeWeaponFocusId,
greaterWeaponFocusId,
greaterWeaponFocusKey,
mythicWeaponFocusKey,
mythicWeaponFocusId,
racialWeaponFocusKey,
weaponFocusId,
weaponFocusKey,
} from "./ids.mjs";

const allKeys = [weaponFocusKey, greaterWeaponFocusKey, mythicWeaponFocusKey];

registerSetting({ key: weaponFocusKey });
registerSetting({ key: greaterWeaponFocusKey });
registerSetting({ key: mythicWeaponFocusKey });

class Settings {
static get weaponFocus() { return Settings.#getSetting(weaponFocusKey); }
static get greater() { return Settings.#getSetting(greaterWeaponFocusKey); }
static get mythic() { return Settings.#getSetting(mythicWeaponFocusKey); }
// @ts-ignore
static #getSetting(/** @type {string} */key) { return game.settings.get(MODULE_NAME, key).toLowerCase(); }
}

// register hint on item with focus
registerItemHint((hintcls, _actor, item, _data) => {
const /** @type {Hint[]} */ hints = [];
allKeys.forEach((key) => {
const current = item.getItemDictionaryFlag(key);
if (current) {
hints.push(hintcls.create(`${current}`, [], {}));
}
});
return hints;
const key = allKeys.find((k) => item.system.flags.dictionary[k] !== undefined);
if (!key) {
return;
}

const currentTarget = getDocDFlags(item, key)[0];
if (!currentTarget) {
return;
}

const label = `${currentTarget}`;

const hint = hintcls.create(label, [], {});
return hint;
});

// register hint on focused weapon/attack
Expand All @@ -41,18 +59,29 @@ registerItemHint((hintcls, actor, item, _data) => {

const baseTypes = item.system.baseTypes;

const helper = new KeyedDFlagHelper(actor, weaponFocusKey, greaterWeaponFocusKey);
const helper = new KeyedDFlagHelper(actor, weaponFocusKey, greaterWeaponFocusKey, mythicWeaponFocusKey);

let label;
if (intersects(baseTypes, helper.valuesForFlag(greaterWeaponFocusKey))) {
label = localize(greaterWeaponFocusKey);
}
else if (intersects(baseTypes, helper.valuesForFlag(weaponFocusKey))) {
label = localize(weaponFocusKey);
}
const isFocused = intersects(baseTypes, helper.valuesForFlag(weaponFocusKey));
const isGreater = intersects(baseTypes, helper.valuesForFlag(greaterWeaponFocusKey));
const isMythic = intersects(baseTypes, helper.valuesForFlag(mythicWeaponFocusKey));

if (label) {
return hintcls.create(label, [], {});
if (isFocused || isGreater || isMythic) {
const tips = []
let bonus = 0;
if (isFocused) {
tips.push(localize(weaponFocusKey));
bonus += 1;
}
if (isGreater) {
tips.push(localize(greaterWeaponFocusKey));
bonus += 1;
}
if (isMythic) {
tips.push(localize(mythicWeaponFocusKey));
bonus *= 2;
}
tips.push(localize('dc-mod', { mod: signed(bonus) }));
return hintcls.create('', [], { icon: 'fas fa-sword', hint: tips.join('\n') });
}
});

Expand All @@ -74,16 +103,19 @@ function getAttackSources(item, sources) {
let value = 0;
let name = localize(weaponFocusKey);

const weaponFocuses = getDocDFlags(actor, weaponFocusKey);
const greaterWeaponFocuses = getDocDFlags(actor, greaterWeaponFocusKey);
const helper = new KeyedDFlagHelper(actor, weaponFocusKey, greaterWeaponFocusKey, mythicWeaponFocusKey);

if (baseTypes.find(bt => weaponFocuses.includes(bt))) {
if (baseTypes.find(bt => helper.valuesForFlag(weaponFocusKey).includes(bt))) {
value += 1;
}
if (baseTypes.find(bt => greaterWeaponFocuses.includes(bt))) {
if (baseTypes.find(bt => helper.valuesForFlag(greaterWeaponFocusKey).includes(bt))) {
value += 1;
name = localize(greaterWeaponFocusKey);
}
if (baseTypes.find(bt => helper.valuesForFlag(mythicWeaponFocusKey).includes(bt))) {
value *= 2;
name = localize(mythicWeaponFocusKey);
}

if (value) {
sources.push({ value, name, modifier: 'untyped', sort: -100, });
Expand All @@ -106,17 +138,24 @@ function addWeaponFocusBonus({ actor, item, shared }) {
const baseTypes = item.system.baseTypes;
let value = 0;

const helper = new KeyedDFlagHelper(actor, weaponFocusKey, greaterWeaponFocusKey);
const helper = new KeyedDFlagHelper(actor, weaponFocusKey, greaterWeaponFocusKey, mythicWeaponFocusKey);
let key = '';

if (baseTypes.find(value => helper.valuesForFlag(weaponFocusKey).includes(value))) {
if (intersects(baseTypes, helper.valuesForFlag(weaponFocusKey))) {
value += 1;
key = weaponFocusKey;
}
if (baseTypes.find(value => helper.valuesForFlag(greaterWeaponFocusKey).includes(value))) {
if (intersects(baseTypes, helper.valuesForFlag(greaterWeaponFocusKey))) {
value += 1;
key = greaterWeaponFocusKey;
}
if (intersects(baseTypes, helper.valuesForFlag(mythicWeaponFocusKey))) {
value *= 2;
key = mythicWeaponFocusKey;
}

if (value) {
shared.attackBonus.push(`${value}[${localize(weaponFocusKey)}]`);
shared.attackBonus.push(`${value}[${localize(key)}]`);
}
}
Hooks.on(localHooks.actionUseAlterRollData, addWeaponFocusBonus);
Expand All @@ -141,11 +180,15 @@ Hooks.on('renderItemSheet', (
const isGreater = (name.includes(Settings.weaponFocus) && name.includes(Settings.greater))
|| sourceId.includes(greaterWeaponFocusId)
|| item.system.flags.dictionary[greaterWeaponFocusKey] !== undefined;
const isMythic = (name.includes(Settings.weaponFocus) && name.includes(Settings.mythic))
|| sourceId.includes(mythicWeaponFocusId)
|| item.system.flags.dictionary[mythicWeaponFocusKey] !== undefined;
const isRacial = sourceId.includes(gnomeWeaponFocusId)
|| item.system.flags.dictionary[racialWeaponFocusKey] !== undefined;

if (isGreater) {
if (isGreater || isMythic) {
key = greaterWeaponFocusKey;
key = isGreater ? greaterWeaponFocusKey : mythicWeaponFocusKey;

if (actor) {
choices = getDocDFlags(actor, weaponFocusKey).map((x) => `${x}`);
Expand Down
2 changes: 1 addition & 1 deletion src/targeted/bonuses/damage-bonus.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export class DamageBonus extends BaseBonus {

sources = (conditional.modifiers ?? [])
.filter((mod) => mod.target === 'damage')
.map((mod) => conditionalModToItemChange(conditional, mod, { isDamage: true }))
.map((mod) => conditionalModToItemChange(conditional, mod, { isDamage: true, rollData: target.getRollData() }))
.filter(truthiness);

return sources;
Expand Down
5 changes: 3 additions & 2 deletions src/util/conditional-helpers.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,10 @@ export function conditionalCalculator(shared, conditional) {
* @param {ItemConditionalModifier} modifier
* @param {object} [options]
* @param {boolean} [options.isDamage]
* @param {RollData?} [options.rollData]
* @returns {Nullable<ItemChange>}
*/
export function conditionalModToItemChange(conditional, modifier, { isDamage = false } = {}) {
export function conditionalModToItemChange(conditional, modifier, { isDamage = false, rollData = null } = {}) {
if (!modifier) return;

const subTarget = modifier.target;
Expand All @@ -92,7 +93,7 @@ export function conditionalModToItemChange(conditional, modifier, { isDamage = f
operator: 'add',
priority: 0,
subTarget,
value: modifier.formula,
value: rollData ? RollPF.safeTotal(modifier.formula, rollData) : modifier.formula,
});
if (isDamage) {
change.type = modifier.type;
Expand Down
Loading

0 comments on commit d3973b7

Please sign in to comment.