#Pondering the DexBonus

1 messages · Page 1 of 1 (latest)

hidden zenith
#

@wild pebble

wild pebble
#

Good thinking lol. Polluted the main channel plenty

#

Gonna grab the code block

const armorType = armors[0].system.type.value;
const baseDexBonus = CONFIG.DND5E.armorKey[armorType]?.maxDex ?? Infinity;
const currDexBonus = (armorData.dex ?? baseDexBonus) - baseDexBonus;
const potentialDexBonus = this.system.attributes.ac.bonuses[armorType] ?? 0;
ac.dex = baseDexBonus + Math.min(this.system.abilities.dex?.mod ?? 0, Math.max(currDexBonus, potentialDexBonus));
hidden zenith
#

The simplest case to handle is probably when the item has a dex cap set.

wild pebble
#

In that case, do we treat that cap as the base, or have we decided the base is always the CONFIG default

hidden zenith
#

From a user standpoint, they'd probably want a simple and single property to configure via an AE.

wild pebble
#

Should an override in an AE always win, then? Or are overrides a weird use case here

hidden zenith
#

AEs would apply in their normal order of priority

#

They would just target the same property, and the final number if what would be used to determine the dex bonus

wild pebble
#

Yeah, I meant vs the set value on the armor item. Unless you're thinking HB's way where all non-special armor gets a null value

#

Which honestly wouldn't be the worst migration script, just comparing the set value against the new CONFIG defaults and removing if the same

hidden zenith
#

OK, so either (1) the item has a value set if it is meant to be explicit or (2) it has an empty input to defer to the config object

wild pebble
#

Yeah that's cleanest I think

hidden zenith
#

The system has certainly done worse changes for the end user to accomodate.

wild pebble
#

Most people probably won't even notice the change lol

hidden zenith
#

So if the AE is 7 and the armor has a value of 2, what should that be taken to mean?

wild pebble
#

I'd say upgrade to 7. Generally I'd imagine the set value would only be for "this is better than usual" - not for worse. Though upon reflection, the entire field could be done away with, with magical armor that has a differing dex maximum just having an AE on it

#

I think my "upgrade to 7" is wrong though

hidden zenith
#

Well is it meant to be "7 more than usual" or set to 7?

#

The basic idea is support for features that let you increase your armor dex bonus from 2 to 3

wild pebble
#

Maybe "7 more than default"?

#

Okay, okay I think it'd go to 9 in the example, then

#

Max dex mod: actor data value + (armor value ?? armor default)

#

So long as the value in the actor's data is 0 by default regardless of armor type, I think that formula would account for everything

#

If no AE, you get the armor value, or the default for the armor if that's not there. If AE, apply it to whatever you'd normally be getting (again, the armor value if there, else the default). Special treatment for a null default

hidden zenith
#

Yeah makes sense.

wild pebble
#

Hm. I guess with light armor there'd be no way to set an actor-specific debuff for it though. I think that's fine

#

If you have max dex to light armor, it's probably because of the specific armor, not some condition

hidden zenith
#

I think that's probably the way to go: if the type of armor does not have a cap, it cannot be modified

wild pebble
#

Cool, so:

const armorType = armors[0].system.type.value;
const currDexBonus = armorData.dex ?? CONFIG.DND5E.armorKey[armorType];
const maxDexBonus = currDexBonus ? currDexBonus + (this.system.attributes.ac.bonuses[armorType] ?? 0) : Infinity;
ac.dex = Math.min(this.system.abilities.dex?.mod ?? 0, maxDexBonus);
hidden zenith
#

Looks good

wild pebble
#

Neat. Will see about trying to implement tomorrow, if you don't go for it

hidden zenith
#

This placeholder should be changed as well.

wild pebble
#

Ah yeah. Just grab from the config

hidden zenith
#

This does mean there's no need for a migration, I think?

#

If a value is set in the item, it can remain.

wild pebble
#

Huh. I thought we'd still need to clear out the ones that match the default but looking at the second line I wrote maybe not after all

hidden zenith
#

One thing this changes, though, is that any medium armor with no value in that field will be treated as having a cap.

wild pebble
#

That's true. That I suppose could be migrated. Though I guess the solution would be to give it like 100

#

Or a "no max dex" checkbox but I 1. Hate that and 2. Think it's overkill

hidden zenith
#

That is what I was thinking though

#

Could be added to the Properties set.

wild pebble
#

I mean uh I love it

#

Okay actually in properties I don't hate it

#

I was picturing it beside the existing input box

#

How many RAW medium armor sets have no cap?

hidden zenith
#

Anything with no value set would be migrated to have "Unlimited Dexterity" (or a better name) checked in system.properties

#

Not many. Probably none.

#

But I think that's besides the point.

#

Right now you can make medium armor with no cap, and we shouldn't suddenly break that item.

#

Ideally, at least. Not like it has not happened before. And would be an easy fix if a new property was added.

wild pebble
#

Yeah agreed. Was just curious how many items would be impacted by such a migration

#

Probably need a different name than just .bonuses.heavy for instance though - that looks like it means extra AC when wearing heavy armor

hidden zenith
#

ac.ability.light, .medium, .heavy

wild pebble
#

That'll do it

wild pebble
#

Also - such a property would have to be valid appear for all Equipment, right? Unless filtering was done on the properties in the template itself?

wild pebble
#

And finally (I think) - where would the migration go for armor with no currently set max dex bonus? Just peeking around it looks like there's generally 2 types of migration, a lazy version that happens each time an item is opened (not ideal here, since we do want to let people leave it empty without it automatically going unlimited dex bonus) and one that goes on a new system version - but I'm not 100% sure I'm right about that

hidden zenith
hidden zenith
wild pebble
#

Ah cool, will take a peek for the latter

#

Went with noMaxDex for the property name but definitely not married to it

hidden zenith
hidden zenith
wild pebble
#

Works for me, will change along with the property filtering

hidden zenith
#

I had a PR once to do similar changes to armor, and part of it was to add the ability to change what Ability was used rather than hardcode it to Dexterity. If someone did something like that in the future, it would be nice if the property did not have 'dex' in the name.

wild pebble
#

That makes sense, yeah

wild pebble
#

General style question for the repo - there a preference between

ac.ability = Object.fromEntries(Object.keys(CONFIG.DND5E.armorMaxDex).map(i => [i, ""]))
``` and
```js
ac.ability = {};
for ( const type in CONFIG.DND5E.armorMaxDex ) {
  ac.ability[type] = "";
}
hidden zenith
#

Well the first is 3 loops, isnt it? The fromEntries, the .keys and the map

wild pebble
#

Ah yeah it is. Fewer lines, worse performance. Good point

hidden zenith
#

I get shit on for my syntax all the time, but I would--

ac.ability = {};
for ( const k of Object.keys(CONFIG.DND5E.xxx) ) ac.ability[k] = "";
wild pebble
#

I may do that - I don't like doing a for in if I can avoid it

#

Gotta run (away from PC at least) but put in the name changes & cleaned up a bit. Agreed it might make sense to merge with armorTypes but will also have to look at where that actually gets used to see how complex of a change that'd be

wild pebble
#

Thinking idly - could probably just make the existing values into objects with label properties and leave shield without a maxAbilityBonus property or whatever - technically we'd then potentially run into a "undefined vs null" if someone were to check for armorTypes[someType].maxAbilityBonus, but I don't think that would matter. The system would only check it for an actual (non-shield) armor item

hidden zenith
#

Sounds fine to me.
The object should, at the very least, contain nested objects. Flat enums are a no-no.

#

Did you consider the case where the worn armor is not light/medium/heavy? Actually not sure that's even possible, though, come to think of it.

wild pebble
#

Natural, or something added via world script, are I think the only other options. But if a null or undefined value is found when doing AC calc it'll treat it as infinite if there's no default.
I was thinking armorTypes.heavy would be { label: "theExistingValue", maxAbility: 0 } for instance - that's what you mean by nested?

hidden zenith
#

Yes

#

There is a patchConfig method you can use for this migration

wild pebble
#

Ah yeah I guess this wouldn't have been the first time something like this gets updated

hidden zenith
#

No, it's happened about 50 times

#

I think all the objects were flat at some point.

wild pebble
#

At this point new ones should probably be too just to save effort later lol

wild pebble
#

Only places I can find that make use of CONFIG.DND5E.armorTypes:
In config.mjs:

DND5E.equipmentTypes = {
  ...DND5E.miscEquipmentTypes,
- ...DND5E.armorTypes
+ ...Object.values(DND5E.armorTypes).map(t => t.label)
};
```proposed change above

In `migration.mjs` & `actor.mjs`:
`Object.keys(CONFIG.DND5E.armorTypes)` (can be ignored, keys aren't changing)

In `eqipment.mjs`:
`return this.type.value in CONFIG.DND5E.armorTypes;` (can be ignored, same reason)

In `item-sheet-2.mjs`:
```diff
context.equipmentTypes = [
  ...Object.entries(CONFIG.DND5E.miscEquipmentTypes).map(([value, label]) => ({ value, label })),
- ...Object.entries(CONFIG.DND5E.armorTypes).map(([value, label]) => ({ value, label, group: "DND5E.Armor" }))
+ ...Object.entries(CONFIG.DND5E.armorTypes).map(([value, { label }]) => ({ value, label, group: "DND5E.Armor" }))
];
```proposed change above

In `equipment.hbs`:
```diff
<optgroup label="{{ localize "DND5E.Armor" }}">
-   {{selectOptions config.armorTypes selected=system.type.value}}
+   {{selectOptions config.armorTypes selected=system.type.value labelAttr="label"}}
</optgroup>
```proposed change above

Then there's this, in `starting-equipment.mjs`, and I'm not entirely sure what modification would be necessary:
```js
static CATEGORIES = {
  armor: {
    label: "DND5E.Armor",
    config: "armorTypes"
  },
  focus: {
    label: "DND5E.Focus.Label",
    config: "focusTypes"
  },
  tool: {
    label: "TYPES.Item.tool",
    config: "toolTypes"
  },
  weapon: {
    label: "TYPES.Item.weapon",
    config: "weaponProficiencies"
  }
};

Checking to see how this is used now

#

(Also, in retrospect, this could just have been another push to the PR, so feel free to ignore & evaluate once pushed)

wild pebble
#

Okey, all done now. Would appreciate a review if you have the time, to make sure I haven't done anything dumb

hidden zenith
#

Already looked at it, no immediate problems stood out to me.

#

It's all in Kim/Arbron's hands now

wild pebble
#

Sounds good, thanks

hidden zenith
#

Are there first-party instances of bonuses that apply only when wearing light armor or no armor?

wild pebble
#

I can't think of any single bonus that would apply to either both. Though admittedly my time spent actually playing/being familiar with dnd is dwarfed by my time coding for it so I’m not at all confident about that

wild pebble
#

There are a good chunk of the unarmored ones that only apply if also un-shielded (like bracers of defense)

#

But probably beyond the scope of this PR to try to account for that. An "unshielded" bonus is fine, but then might need armored unshielded and unarmored unshielded. Too many keys

wild pebble
#

Mm. Swashbuckler (monster not subclass). Suave Defense: add cha mod to AC when wearing light armor or no armor. Though as that's not a PC, unlikely to necessitate these attributes needing to be set

hidden zenith
#

Thanks for checking. We have seen examples in premium content as well, so I'm not sure that it's not worth looking into.

wild pebble
#

I guess a potential solution would be splitting the armored bonus into armor types, like the max ability one?

hidden zenith
#

There's precedent, for sure. Like how attack/damage bonuses are split.

#

However, I think it makes sense to have both.

wild pebble
#

Yeah true, better not to have 3 keys need to be set for just one effect

hidden zenith
#

ac.bonuses.unarmored, .armored, .light, .medium, .heavy, .shield

wild pebble
#

That second one supposed to be .armored?

hidden zenith
#

Maybe it's worth it to ping Arbron or Kim on the PR and get their input.