#SWADE Targeted Damage
1 messages · Page 1 of 1 (latest)
Well, PF2e is the ulimate in terms of 'smoothness' imo
Of course. Just wanted to see what might be feasible
In that its:
Target enemy, press attack roll button
Module then automatically applies modifiers, range, blinded, etc, and outputs the result.
Module then also does the damage roll on the targeted enemy.
Currently, with raise calculator and targeted damage, its:
Target enemy, roll attack roll
Open raise calculator and do the thing
Go back to the weapon/power message and roll damage
Click resolve damage and fill out the box
Having the resolve damage box popping up automatically is probably the most you can do without also reworking the entire module to do everything attack and damage related
Yeah, part of the challenge is that there are things like spending a Benny to reroll your attack, like if you succeed with a hit, but you really want that raise, or if there's some conditional that's not accounted for that would influence success, failure, or raises. PF doesn't have any of that. It's very binary. You hit or you don't (excluding conditional modifiers of course).
Hm, I see your point, there's a lot more choices regarding each roll rather than static numbers
I considered adding a similar workflow to attack rolls. Roll while a target is selected, prompt for adjustments like weaknesses or unaccounted modifiers, and then including damage roll buttons on the attack result chat card.
Better rolls 4 swade was the best for applying modifers imo
Copying that, where modifiers are openly laid out at the time of rolling the attack, would be the most user friendly option
It does a really good job of that. I personally struggle with the layout of all those modifiers though. It feels overwhelmingly cluttered in a chat card. I've wanted to at least learn how to handle range and possibly illumination based on scene lighting conditions. (SWADE uses more levels of lighting than Foundry can handle, IIRC. Specifically, Bright, Dim, Dark, and Pitch Black versus Bright, Dim, and Pitch Black.)
It seems like though that managing a workflow for attack rolls like they're handled for damage rolls could be a starting point. As a starting point, give an opportunity to prompt for adjustments to the final roll result. Then, at some point in the future, see about autogettiing modifier values based on data on the token, actor, or scene.
I think the damage portion is fine right now, maybe change the 'close' button to 'finalise' or something for clarity ( I didn't realise how to 'apply' the damage at the beginning ) but I honestly couldn't ask for more
I'm not sure I follow. Once you take a wound or apply shaken, it should close automatically. At what stage does present 'close'?
Sorry, guess I mis-remembered what it said
Hmmm... I might relabel Submit to "Apply Adjustments".
So for clarity, did you find Apply Shaken Status to be unclear with respect to what would happen or was it because of the context of the Submit button?
I think it was the 'submit' and 'apply' buttons both kinda implying the same thing
This MR has expanded beyond Regions and includes Gang Up and many other standard modifiers
https://gitlab.com/peginc/swade/-/merge_requests/870
While still not Better Rolls, it covers a lot of ground
Oooh! Michael's tearing it up over there.
I'm curious about illumination. I can see scene regions contributing to that, but I still want to explore if scene global illumination can be accounted for, too.
I think I have an idea for illumination penalties. I'm considering adding a setting where you can set the a series of values for bright, dim, and dark darkness values. Pitch Black would just be whatever the threshold is configured to be on the scene. I could then have a small script that modifies the translation string for the darkness setting description text to include the values set for reference. At that point, when an attack is rolled, the module could check the current level of darkness, whether the target token is in light, the brightness of that light, and apply illumination penalties (if any).
Getting Scene.environment.darknessLevel and comparing will be easy enough. It's checking if a Token is in light that I'll struggle with.
this is also something we can bug Core about
like, we're not exactly the only ones who care about illumination
I had a whole post I wrote up that I was going to post about it, but I figured it's not likely going to happen anytime soon anyway.
Figured I'd just try to put it in a module, and if it inspires others to do something similar, cool.
You know, I might even be able to just derive dim and dark based on whatever the darkness threshold is set to. just slice the difference into halves. 0 is bright, threshold is pitch black, threshold to 49% of diff is dark. 50% of diff to 0.05 is dim.
Should definitely document
Next, read the values during an attack roll.
Working...
Hooks.on('preUpdateScene', (scene, changed, options, userId) => {
if (game.userId !== userId) return;
if (!changed.tokenVision) {
changed['flags.swade-targeted-damage.illumination'] = null;
return;
}
const pitchBlack = changed.environment.globalLight.darkness.max;
const illuminationRollModifiers = CONFIG.SWADE.prototypeRollGroups.find((rollGroup) => rollGroup.name === game.i18n.localize('SWADE.Illumination._name'))?.modifiers;
const darknessLevel = changed.environment.darknessLevel;
let illuminationMod;
if (darknessLevel >= pitchBlack || !changed.environment.globalLight.enabled) {
illuminationMod = illuminationRollModifiers.find((m) => m.label = game.i18n.localize('SWADE.Illumination.Pitch'));
} else if (darknessLevel >= pitchBlack / 2) {
illuminationMod = illuminationRollModifiers.find((m) => m.label = game.i18n.localize('SWADE.Illumination.Dark'));
} else if (darknessLevel >= 0.05) {
illuminationMod = illuminationRollModifiers.find((m) => m.label = game.i18n.localize('SWADE.Illumination.Dim'));
} else {
illuminationMod = null;
}
changed['flags.swade-targeted-damage.illumination'] = illuminationMod;
});
const swadePreRollHookEvents = ['swadePreRollSkill', 'swadePreRollAttribute'];
for (const hookEvent of swadePreRollHookEvents) {
Hooks.on(hookEvent, (actor, skill, roll, modifiers, options) => {
const token = game.scenes.current.tokens.find((t) => t.actorId === actor.id);
const illuminationModifier = game.scenes.current.getFlag('swade-targeted-damage', 'illumination');
if (token && illuminationModifier) {
const hasBrightLight = token.light.bright > 0;
const hasDimLight = token.light.dim > 0;
if (!hasBrightLight && !hasDimLight) {
modifiers.push(illuminationModifier);
}
}
});
}
If those illumination modifier objects are stored anywhere in the system, I'd prefer to get them from there and add on the level to pass it to the flag.
Found them.
@magic sentinel I simplified it some. Let me know what you think.
Another example is that the system doesn't know whether you're making an attack roll or a test to make the target vulnerable or distracted. Right now I'm trying to figure out how I might be able to determine when to consider whether the target is in light or the acting token is in light and whether to consider adding a penalty or not. I think at best I can just add the modifier to the roll and let the user deactivate the modifier if needed.
Demo time:
I think that's all you can and should do. Cause someone may have something that negates or reduces penalties etc.
It at least accounts for whether the Token has its own light. If it has any bright or dim light, it won't apply the modifier at all.
I could set it to apply it but not have it active, just in case, but that might be confusing.
https://github.com/foundryvtt/foundryvtt/issues/10023 the spot to bug core. And a reminder from Mana about canvas.effects.getDarknessLevel() which doesn't care about lights but would take into account "adjust darkness level" regions
There's also a "are you in the radius of a dim light source" and "are you in the radius of a bright light source" bit of code I've used (basically iterating over all lights on the scene) but that doesn't account for multiple sources of stacked dim light or anything
Hoo boy do I have the hook for you! At least, if/when that above MR goes in, https://gitlab.com/peginc/swade/-/merge_requests/870/diffs#048234a314b1643df2dac95859d24be0019d95b4_415_582 (don't mind the ugly permalink). You'd be able to
- See if any region with illumination is set (if so, probably defer to that)
- If not, add your own modifier in
Come to think of it maybe I should provide the bestCover and bestIllumination in an object so that they too can be mutated by listeners (eg if the system says "no penalties" and you say "actually dark" and then some other module comes along and wants to say "no, dim" it would be able to know what the "current" - as determined by you - illumination modifier is)
@small sail You're blowing my mind. I have clarification questions, but I need coffee and to take care of a few work things first.
So if my coffee is working and I'm understanding things correctly, canvas.effects.getDarknessLevel(Token.getSnappedPosition()) should get the darkness level to determine illumination penalties for the given token. Then I could assume that if the user has a targeted token, to include that token's illumination. I could then add both modifiers and allow the user to deactivate whichever one doesn't apply.
Potentially, depending on how you wanna do the logic. getDarknessLevel purely takes into account the literal "darkness level," so the majority of the time it'd be identical to the scene's environment.darknessLevel; the only time that's not the case is if there's a region with the "Adjust Darkness Level" behavior, and the position you're checking is in that region
Example (hovered text is the result of getDarknessLevel on the hovered token)
It doesn't account for light sources though?
Right, for that you'd need some other special logic
Something like:
function getLightLevel(token) {
let c = Object.values(token.center);
let lights = canvas.effects.lightSources.filter(src => !(src instanceof foundry.canvas.sources.GlobalLightSource) && src.shape.contains(...c));
if (!lights.length) return 'dark';
let inBright = lights.some(light => {
let {data: {x, y}, ratio} = light;
let bright = ClockwiseSweepPolygon.create({'x': x, 'y': y}, {
type: 'light',
boundaryShapes: [new PIXI.Circle(x, y, ratio * light.shape.config.radius)]
});
return bright.contains(...c);
});
if (inBright) return 'bright';
return 'dim';
}
``` (use that in CPR; haven't looked at it since acquiring a higher understanding of canvas things yet though)
Naturally, that's not ideal for two reasons:
- Doesn't care if you have 50 dim lights on you, you're still only in "dim"
- SWADE (as mentioned before) has a greater determination than just "bright, dim, dark."
Perfect world, there'd be a function that would sum the cumulative light levels and spit out a hard number
Re: bright. dim. dark, that's why I derive the levels between the threshold (pitch black), and 0 (bright).
Bright === 0 < Dim < Threshold / 2 <= Darkness < Threshold <= Pitch Black
I'll give this a shot
You could probably adjust the above function to tell you the number of dim lights you're in (presumably if you're in any bright light you're well lit), if that'd be relevant
I'm considering that.
So I don't really need to set the flags in preUpdateScene then.
Originally I had it storing the various darkness levels for each Illumination modifier. That might still be useful.
Yeah you could technically just grab the darkness threshold from the scene each time; storing "the" illumination modifier in the flag wouldn't necessarily make sense now that you're accounting for local illumination
My idea was to store each Illumination level's value range so when you want to determine which modifier to apply, you just check the value from getDarknessLevel against those ranges since the Threshold can vary scene to scene. If it matches, you've then got the modifier details for the roll already in the same object.
Yeah that'd be clean. Guess it's either that or grabbing the threshold and doing the math each time, and constructing the modifier each time (which is one of the things I think could do with some refactoring at some point in the future)
That's what I started doing, and then I was like, "Why not just store this?!" 😆
Yeah in the MR linked above I'm building them all in-place, but would be neat to be able to do CONFIG.SWADE.prototypeRollGroups.illumination.dim for instance to get back the RollModifier for dim illumination
Example:
[
{
"label": "Dim Light",
"value": -2,
"levels": {
"max": 0.375,
"min": 0.05
}
},
{
"label": "Darkness",
"value": -4,
"levels": {
"max": 0.7999999999999999,
"min": 0.425
}
},
{
"label": "Pitch Black",
"value": -6,
"levels": {
"max": 1,
"min": 0.85
}
}
]
need to trim those decimals
Just a heads up, token.center is undefined, but token.object.center has a value.
Ah right, that function expects the placeable as input not the document
Ah, I see.
I'm thinking if there's more than one dim light source intersecting with the token's center, consider it bright.
That seems reasonable to me
Very reasonable but in some ways not supported by the rules where the GM would say whether that is true or not rather than a formula
Which makes it hard to put in the system proper
Yeah, and in actuality, it doesn't look any brighter on the scene.
That token is in the dim overlap of all of those light sources, but it's no brighter than any other dim area.
So maybe it should represent what the user sees and just treat it as dim regardless.
It can be overridden in the roll dialog anyway
I think that is most Savage
Does this take into account light sources from other tokens?
Good point, I don't think so. Nor for that token itself. Purely light sources (I think)
I've already accounted for the token's own light
The labels could be clearer, but here's the idea.
Global Darkness and Nearby Light perhaps
If the token is in a bright light source.
Neat, yeah I can see that being handy
So now if it has its own light source or if it's in nearby scene light(s), it still includes the global illumination modifier but it's set to ignore by default.
Here's the code so far
I like that. I was considering something similar and also trying to make use of vision modes or something but figured that was a step too far for a system implementation. The "ignore by default" is (imo) a good solution for "this might apply, but it might not"
The next thing is to check for targeted tokens and their lighting situations and add another "this might apply" modifier.
But I think I'll only account for the token in the darkest condition.
I would argue that for attacks specifically, the attacking token's illumination isn't ever gonna be relevant
(If no tokens are targeted then it's a solid fallback though)
Right, the problem is, you never know 100% if the roll is an attack
or if they aren't targeting something and can't check the lighting
it's just a hot mess of possibly maybe
True - the best I've managed so far is:
const isAttack = options.item?.type === 'weapon';
const { isRanged=null, isMelee=null } = options.item?.system ?? {};
const isRangedAttack = isRanged && (!isMelee || (skill?.system.swid !== 'fighting'));
const isMeleeAttack = isMelee && (!isRanged || (skill?.system.swid === 'fighting'));
``` which doesn't factor in powers at all. You can _basically_ guarantee that it _is_ an attack if `isAttack` is true, but there are times where it _won't_ be true that it still is one
Without code, that's about as far as I got in my head
I yoinked the first bit of logic from RollDialog#isAttack
Figured hey if it's good enough that we show the attack modifiers in the roll dialog dropdown, it's good enough to auto-add em
I just realized an issue with the flags approach. A script (module, system, or macro) could modify the darkness levels, which wouldn't be captured in the flags.
Hmm. Remind me what you're storing as a flag now? Away from PC so can't read the code prettily
Oh, I was capturing the modifier data but with min and max darkness values for each.
Ah I see. Hmm
I'm just gonna do the comparisons in the preRoll hook events
Probably safer there
Good news. It does include token light. Three possible sources are Global, which is excluded in the function, Ambient and Token, so it's getting both Ambient and Token. Tested it and it works.
Need an opinion and then I'm off to bed. The Actor has a Dim light source and is targeting 4 other tokens. One of the other tokens also has a Dim light source and another is within range of that Dim light source. The other two are in Pitch Darkness. Which of these three roll dialogs makes the most sense in terms of what the penalties are attributed to?
#2 I think?
Token, Target, Ambient?
And why that one over the others, just so I know what qualities make it better?
For me, I'm associating the ambient with ambient lights
Ah, so you didn't know that it was also including other tokens with light?
Hmm yeah maybe that's a good reason not to use ambient
Which tells me Proximity doesn't mean anything, but perhaps "Ambient/Token" or "Ambient & Token"?
Then Actor was implying the acting Actor's own light.
OK, so I'm getting all targets and assessing their lighting conditions. No issues there. However, now I'm getting some duplicate modifier entries, and I want to include only unique ones. Nothing I do seems to generate a unique set of modifiers. I've tried the converting it to a Set and back trick. No, luck. Built a new array and assigned it to modifiers, still no luck.
I think I've been overthinking it. This is what we really need to know.
I think I'll roll this out as a beta feature disabled by default and collect feedback.
SWADE Targeted Damage v3.1.0
- New Feature - Suggested Illumination Penalties (Beta): Adds inclusion of Illumination Penalties to Trait rolls based on the current Scene's global illumination settings and darkness levels as well any Dim lighting the Token is currently in.
- The calculation for Dim, Darkness, and Pitch Dark is based on the Global Illumination Threshold Setting on the Scene. If the Scene's current darkness level is greater than or equal to the threshold, it's considered Pitch Dark. Dim is applied if there's any amount of darkness on the scene (0.05). Darkness starts at half the threshold value.
- The penalty can be overridden in the Roll Dialog to account for a variety of circumstances in which the penalty might be lessened or not apply at all.
- This feature is disabled by default and can be enabled in the module's settings.
- If you run into any issues with this feature or have suggestions for improvements, please submit an issue on GitHub.
I like it and some quick tests have it working well. You may (or may not) want to incorporate looking through the source actor's item SWIDs for the common limits to illumination penalties (low-light-vision, darkvision, night-vision) and ignore certain illumination penalties based on what you find.
if you're interested in expanding this, I have a private module that does similar for Deflection (based on active effect), Vulnerable, Glow/Shroud (based on AEs also), Arcane and Environmental Resistince/Weakness, Gang Up, Scale, Range, and Dodge, with preTraitRoll and preDamageRoll hooks for targeted things. It's a little wonky and not localized 'cause it's only me using it, but I could share.
I haven't cleaned it up and released it mostly 'cause I didn't want to compete with BR2 or swade tools in that space... but if YOU want to do a closer-to-system-default-rolls automation tool I won't get in the way.
and I'd be happy to contribute 🙂
I like the idea, but it assumes the SWIDS will be identical (i.e., dark-vision vs darkvision). I'd need to research if those are consistent across settings.
some of my private module gets REALLY close to the edge of coding game behavior from the copyrightable rule set as well, so I've been worried about releasing it for that reason as well.
I might be able to create a config setting where a GM could create those pairs themselves. Default to the core and FC, and allow others to be added.
I should jump in and mention that I've done some work in the system (not yet merged, but should be) that hits some of those areas, pre-attack only currently, and handling of illumination specifically is relegated to a new region type so there's no incompatibility, but in terms of stuff like vulnerable, gang-up, scale, range, dodge, etc those should soon(ish) be covered
Nice
I'm happy to contribute to the system for this stuff too, or just share what I've got with you.
(if I contribute to the system it'll finally make this backend programmer learn about this typescript thing the kids are using these days)
https://gitlab.com/peginc/swade/-/merge_requests/870 I'll point you here if you're curious - I haven't addressed things like darkvision in this first pass, part of what's so nice about swade's roll dialog is that it makes it very easy to slap stuff into modifiers and trust the user to know when to uncheck or check the box
yeah it was surprisingly easy to do
The PR started as "illumination regions" and swiftly scope creeped hard
But yeah what'll be neat is that it'll have the ability to define such regions, but it'll also offer a hook for pre-attack specification of roll modifiers (besides the already existing pre trait roll stuff) which'll contain the existing "best cover"/"best illumination" that can be overridden by modules. So for instance if Kristian's implementation wants to toss the system-determined illumination (which, currently, is purely if you've manually set up a region of the new type), it totally can do so
Nice
ok reading this over I'm extremely excited for that to be merged and released 'cause it means I can rip out large portions of my own stuff. Thanks for sharing the sneak peak!
Keep me posted on what I'll need to change, if anything
It should be all good tbh, without intentionally trying to, neither of us should clobber the other
I'm also debating creating an extended Scene sheet that adds slider fields for Dim and Darkness. The max value could be determined by the Threshold value of the others. So for example, Darkness' max value would be the Scene's Pitch Dark Threshold minus 0.05 (maybe even relabel the core Threshold to Pitch Dark). Then Dim's max would be Darkness' Threshold value minus 0.05. And then finally Dim's Threshold could be set to whatever of course.
That'd be a cool way of bending core's darkness settings to the will of the system's rules
As a module, I could either store that data as flags or register a new Scene subtype. Perhaps the system could extend a SwadeScene to add those properties at some point.
Yeah I mean I know John is a fan of a global scene penalty for illumination, that might be a good reason to subtype
It could sorta come automatically with a combo of the actual darkness setting and the threshold settings
Something like this
you'd do that as a scene-specific setting instead of a global setting? Are there cases where the aesthetic look of (say) 0.25 would feel like 'dim' on one scene but not on another?
Scene to scene differences in "default" darkness is part of what would make it so difficult to say "that's dim" without making assumptions. Some maps just have brighter content than others. So being able to specify per-scene would clean up some of that gray area. Though global defaults as a setting would make sense too imo
Fair point.
For sure, one way I use darkness on a scene is more like atmosphere or visual look than actual illumination leels
kinda like adjusting brightness on the image
Now to update the script that determines the suggested illumination penalties.
I'm also debating appending "(Pitch Dark)" to the Global Illumination label
And whether this should be a new module altogether.
"SWADE Auto-Illumination" sounds nice I must say.
It would be cool (I don't know if it's feasible without a buncha extra coding) if the sliders for the thresholds stayed the same width, but whichever section was "off limits" was simply disabled
That gets confusing when your dealing with max values on the slider. There's no way to stop the drag behavior that I'm aware of, but I could be wrong.
Yeah that's the part I was wondering about specifically. I suspect you're right, but looking into the range picker code now just in case
I was wrong. There might be a way
Yeah not very user friendly
Possibly by setting the value on click if it's value is max already
But the user might just think it's broken
An alternative might be to push the others up. So if dim goes up, it pushes darkness up
Ideally it could
- Stop the slider thing early
- Style the out-of-range areas of the slider at least
Now lower levels of darkness can push the thresholds of higher levels of darkness when adjusting the values.
Very nice
I've got the labels and hints customized now.
I'll roll out an update tomorrow. Not sure if I want to break it out into another module simply because I need another module like I need another hole in my head.
But knowing me, I likely will make it a new module. We'll see.
What do you think of "SWADE Illuminator" as the module name?
I like it. I’m famously great at naming things.
Module that lets you attach regions to templates? Region Atttacher.
Module that lets you have a follow-up save activity in dnd5e? Dnd5e follow-up save.
Module that lets you have aura effects? Aura Effects