Skip to content

feat(SmartAoE): Enhances 2024 sheet support and updates help - #2359

Open
steverobertsuk wants to merge 18 commits into
Roll20:masterfrom
steverobertsuk:sr/smartaoe-v1-0-1
Open

steverobertsuk wants to merge 18 commits into
Roll20:masterfrom
steverobertsuk:sr/smartaoe-v1-0-1

Conversation

@steverobertsuk

@steverobertsuk steverobertsuk commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

[1.0.3] – 2026-11-02

A crash fix from user feedback. There are no breaking changes.

Changed

  • The README and help handout explain that SelectManager's !forselected drops inline rolls, so rolls in a !forselected command should be written as <<…>>.

Fixed

  • Inline rolls lost by another Mod no longer crash SmartAoE. SelectManager's !forselected sends the command on with sendChat but without the original message's inline rolls, so a roll such as --damageFormula1|[[(5+?{Cast at what level?})d6]] reached SmartAoE as $[[0]] with no result, and SmartAoE stopped with "Cannot read properties of undefined (reading 'total')". SmartAoE now whispers which roll has no result and suggests <<…>>, which SmartAoE rolls itself.
  • An argument with no |value, such as a bare --instant, no longer stops with "Cannot read properties of undefined (reading 'match')". It is read as an empty value.

[1.0.2] – 2026-10-31

AoEs can stop at walls, from user feedback. There are no breaking changes.

Added

  • --blockedBy|walls stops an AoE at dynamic lighting walls (Jumpgate pathv2 and Legacy path drawings on the walls layer) and at closed doors and windows, so a fireball no longer reaches tokens in the next room just because they are inside its radius. A square is left out when no straight line from the point of origin reaches it past a wall, as the D&D 5e rules say; its centre and four points near its corners are tried, so a square seen through a doorway still counts. Open doors and windows let the AoE through. An origin on the caster's edge is measured from just inside the caster, so a caster standing against a wall is not blocked by it.
  • --blockedBy|walls, spread also lets the AoE flow round corners from square to square, as the 2014 Fireball does, as far as its reach. Without --blockedBy, walls are ignored as before.

[1.0.1] – 2026-10-28

Further D&D 2024 (Beacon) sheet fixes from the forum report. There are no breaking changes.

Added

  • Grid rules by game system, in the README and the help handout — the --minGridArea, --minTokArea, shape and origin settings that match D&D 5e 2014 and 2024, Pathfinder 1e and 2e, Starfinder and other systems, with notes on how creature size affects hits (a Tiny creature in a counted square is hit).

Changed

  • The help handout's 2024 (Beacon) sheets tip no longer says the 5eSTR…5eCHA shortcuts need a custom --saveFormula on the 2024 sheet (they have worked there since 1.0.0); it now gives the Sandbox v1.5 and spell-slot notes.
  • 2024-sheet spell slots count up without a limit. On a 2024 sheet, --resource|lvl3_slots_expended (any level) now counts the slots used up to lvl3_slots_total when no limit is given. In 1.0.0 it counted down, so with no slots used it always said there weren't enough, and casting with one slot used took it back to 0. 2014 sheets, where lvlN_slots_expended holds the slots left, still count down.

Fixed

  • Empty leftover attributes no longer hide 2024 sheet values. A 2024 character can carry legacy attribute objects with the same names as its sheet values, for example after moving a 2014 character to the 2024 sheet or when another mod creates them. An empty npc_immunities (or npc_resistances, npc_vulnerabilities, --ignore or --resource attribute) was used as the value, so a Fire Giant took full fire damage even though a chat roll showed "Fire". An empty legacy attribute is now skipped and the sheet's value used.
  • !smarttrigger before the control token has moved no longer stops with "Cannot read properties of undefined (reading 'x')". The AoE has no squares yet, so SmartAoE whispers to move the control token first.
  • Resistances to nonmagical attacks no longer apply to AoEs. The damage-type check was a plain text search, so a 2014 stat block's "bludgeoning, piercing, and slashing from nonmagical attacks" (a Gargoyle, many devils and lycanthropes) halved or cancelled a bludgeoning AoE. AoEs count as magical, as they already did for Magic Resistance, so these damage types are now ignored. Other damage types on the same line still apply.
  • Magic Resistance is detected on 2024 sheets. A creature with a Magic Resistance feature, such as a Yuan-ti, now rolls its save twice and keeps the higher, shown as A on the card, as on the 2014 sheet. The 2024 sheet keeps its features in one store object, which SmartAoE read as "[object Object]". Only feature names are checked, so text elsewhere on the sheet, such as an item's description, doesn't count.

Version 1.0.0 has been merged into the Roll20 repository, so the
follow-up fixes for D&D 2024 (Beacon) sheets go into a new patch
release.

- Set the script, header and script.json to 1.0.1, and add 1.0.0 to
  previousversions.
- Describe 1.0.1 in the script.json description.
- Add the 1.0.1/ snapshot, matching the root script.
- Add the 1.0.1 changelog section and expect v1.0.1 in TESTING.md.

Signed-off-by: Steve Roberts <steve@shadowcomputers.co.uk>
A 2024 (Beacon) character can carry legacy attribute objects with the
same names as its sheet values, for example after a 2014 character is
moved to the 2024 sheet or when another mod creates them. SmartAoE
used such an attribute even when it was empty, so an empty
npc_immunities hid the sheet's "Fire" and a Fire Giant took full fire
damage, although a chat roll showed the immunity (forum report).

An empty legacy attribute is now skipped and the sheet's value is
read instead. This applies to --resistAttr, --vulnerableAttr,
--immunityAttr, --ignore and --resource. A legacy attribute with a
value is still used, so 2014-sheet games behave as before.

Documented in the README's 2024 sheet section, with a TESTING.md step
that adds an empty npc_immunities to the Fire Giant.

Signed-off-by: Steve Roberts <steve@shadowcomputers.co.uk>
On the 2024 sheet, lvlN_slots_expended holds the slots used, but
without a limit --resource counted it down. With no slots used it
always said there weren't enough, and casting after using a slot took
the count back to 0 (forum report).

When the resource is a 2024-sheet lvlN_slots_expended and no limit is
given, SmartAoE now uses lvlN_slots_total as the limit, so existing
macros such as --resource|lvl3_slots_expended work unchanged. An
explicit limit still takes precedence. 2014 sheets, where the
attribute is a legacy object holding the slots left, still count down.

The help handout, README and TESTING.md describe the default.

Signed-off-by: Steve Roberts <steve@shadowcomputers.co.uk>
Running !smarttrigger before the control token had been moved stopped
with "Cannot read properties of undefined (reading 'x')", because the
AoE has no squares or bounding box until the control token moves.

Such an AoE is now skipped with a whisper asking the GM to move the
control token first. Found while testing the forum report in a live
game; TESTING.md has a matching step.

Signed-off-by: Steve Roberts <steve@shadowcomputers.co.uk>
The tip still said the 5eSTR to 5eCHA shortcuts only work on the 2014
sheet and that the 2024 sheet needs a custom --saveFormula and --dc.
That stopped being true when 1.0.0 learned to read Beacon sheets.

The tip now says to use the Mod Script Sandbox v1.5, that saves,
damage-type attributes, --ignore and --resource read the 2024 sheet,
that spell slots count up to the slot total, and that Magic
Resistance is only detected on 2014 sheets.

Signed-off-by: Steve Roberts <steve@shadowcomputers.co.uk>
DMs asked whether SmartAoE follows the 2014 or the 2024 D&D rule for
which squares an area hits. It follows neither by default:
--minGridArea and --minTokArea decide it, and they default to almost
any overlap.

Add a "Grid rules by game system" section to the README and the help
handout. It gives the settings that match:
- D&D 5e 2024 (half a square);
- D&D 5e 2014 (DMG and Xanathar's template method);
- Pathfinder 1e, D&D 3.5 and Starfinder 1e (far-edge rule);
- Pathfinder 2e and Starfinder 2e;
- systems where any touch counts or only a square's centre counts.

The section also notes that the drawn squares are the ruling, and that
a creature in a counted square is hit however small its token, which
was checked with a Tiny token in a live game.

The README's feature list and Pathfinder tip link to the new section,
and TESTING.md lists it among the handout's sections.

Signed-off-by: Steve Roberts <steve@shadowcomputers.co.uk>
Inline code in the help handout was only set in a monospace font, so
settings such as --minGridArea|0.5 were hard to tell apart from the
text around them.

- Inline code now has a light tint, a thin outline and rounded
  corners. The semi-transparent colours read in both Roll20 light and
  dark mode.
- The grid rules settings and the tips mark their code with
  backticks. A new handoutText helper shows those parts as code chips
  that don't wrap, so a parameter such as --forceIntersection|1 no
  longer breaks after its "--".

Signed-off-by: Steve Roberts <steve@shadowcomputers.co.uk>
Magic Resistance was only detected on 2014 sheets. SmartAoE searches
each attribute's text for "magic resist", but a 2024 (Beacon) sheet
keeps its features in a single "store" attribute that holds an object,
and that object's text is "[object Object]". A Yuan-ti on the 2024
sheet therefore rolled its saves once.

- A new hasBeaconMagicResistance helper looks through the store's
  features for an enabled one whose name includes "Magic Resistance".
  The save is then rolled twice and shown as A, as on the 2014 sheet.
- Only feature names are checked. The store also holds item and spell
  text, and a whole-store search matched a 2024 shop character that
  only sells items mentioning magic resistance.
- The 2014 check is unchanged.

Tested in a live game: a 2024 Yuan-ti Infiltrator rolled two saves and
kept the higher; creatures without the trait rolled once.

The README, the help handout's 2024 tip, the changelog, script.json and
TESTING.md no longer say Magic Resistance is 2014-only.

Signed-off-by: Steve Roberts <steve@shadowcomputers.co.uk>
The damage-type check is a plain text search of the target's
resistance, vulnerability and immunity attributes. A 2014 stat block's
"bludgeoning, piercing, and slashing from nonmagical attacks" (a
Gargoyle, many devils and lycanthropes) contains "bludgeoning", so a
bludgeoning AoE was halved or cancelled even though AoEs are magical.

A new removeNonmagicalDamage helper drops these groups from each value
before the check, in both the "... from nonmagical attacks" and the
"nonmagical bludgeoning, ..." wordings, up to the next semicolon. Other
damage types on the same line still apply, so "cold; bludgeoning, ...
from nonmagical attacks" still resists cold. AoEs count as magical,
which SmartAoE already assumes for Magic Resistance.

2024 stat blocks no longer have nonmagical resistances, so only 2014
creatures were affected. Tested in a live game with a temporary
resistance attribute: bludgeoning was no longer resisted, cold still
was, and the existing resistances, vulnerabilities and immunities were
unchanged.

The README's --resistAttr row, the changelog, script.json and
TESTING.md describe the change.

Signed-off-by: Steve Roberts <steve@shadowcomputers.co.uk>
The previous commit made SmartAoE ignore damage types that are only
resisted from nonmagical attacks, and the README's --resistAttr row
explains this. The help handout's row still only said "attributes
listing the target's defences", so a GM reading the handout wouldn't
know why a Gargoyle's bludgeoning resistance no longer applies.

The handout's --resistAttr / --vulnerableAttr / --immunityAttr row now
says that AoEs count as magical, so those damage types are ignored.

Signed-off-by: Steve Roberts <steve@shadowcomputers.co.uk>
Version 1.0.1 is still in its pull request, so stopping AoEs at walls
goes into a new patch release in the same pull request.

- Set the script, header and script.json to 1.0.2, and add 1.0.1 to
  previousversions; the 1.0.1/ snapshot is left as it was.
- Add the 1.0.2/ snapshot, matching the root script.
- Add the 1.0.2 changelog section and expect v1.0.2 in TESTING.md.

Signed-off-by: Steve Roberts <steve@shadowcomputers.co.uk>
A fireball hit tokens in the next room just because they were inside
its radius. With --blockedBy|walls, the squares of an AoE that no
straight line from the point of origin can reach past a dynamic
lighting wall (pathv2 or path on the walls layer), or a closed door or
window, are left out, as the D&D 5e rules say. The square's centre and
four points near its corners are tried, so a square seen through a
doorway still counts, and open doors and windows let the AoE through.

--blockedBy|walls, spread also lets the AoE flow round corners from
square to square, as far as its reach, as the 2014 Fireball does.

The squares are cut when the AoE is drawn, so the template on the map
shows what will be hit and triggering needs no change. An origin on the
caster's edge is measured from just inside the caster, so a caster
standing against a wall is not blocked by it. AoEs without --blockedBy
are unchanged.

Signed-off-by: Steve Roberts <steve@shadowcomputers.co.uk>
Describe --blockedBy in the README's features, parameters, examples and
tips (walls are checked when the AoE is drawn, so nudge the control
token after opening a door), and add a Walls section to the testing
checklist for Jumpgate and Legacy games.

Signed-off-by: Steve Roberts <steve@shadowcomputers.co.uk>
Version 1.0.2 is still unreleased in the same pull request, so the fix
for a crash reported on Discord goes into a new patch release.

- Set the script, header and script.json to 1.0.3, and add 1.0.2 to
  previousversions; the 1.0.2/ snapshot is left as it was.
- Add the 1.0.3/ snapshot, matching the root script.
- Add the 1.0.3 changelog section and expect v1.0.3 in TESTING.md.

Signed-off-by: Steve Roberts <steve@shadowcomputers.co.uk>
…shing

SelectManager's !forselected sends the command on with sendChat, but the
new message has none of the original's inline rolls. A roll such as
--damageFormula1|[[(5+?{Cast at what level?})d6]] reached SmartAoE as
$[[0]] with no result, and parseArgs stopped with "Cannot read
properties of undefined (reading 'total')".

- substituteInlineRolls now whispers which roll has no result and
  suggests <<...>>, which SmartAoE rolls itself.
- The brackets in that whisper are sent as entities. A literal
  [[formula]] in sendChat text is rolled by Roll20, and the dice error
  crashed the whole sandbox during live testing.
- An argument with no |value, such as a bare --instant, is read as empty
  instead of stopping with "reading 'match'".
- Add Node tests (node:test, no dependencies) and the !forselected
  steps to TESTING.md. The new Playwright cases passed live with
  SelectManager.

Signed-off-by: Steve Roberts <steve@shadowcomputers.co.uk>
Users who run SmartAoE through SelectManager's !forselected need to know
why a [[...]] roll fails and what to write instead.

- Add a tip to the README and the help handout: write rolls in a
  !forselected command as <<...>>, which SmartAoE rolls itself.
- Note the tip in the 1.0.3 changelog and describe 1.0.3 in
  script.json.

Signed-off-by: Steve Roberts <steve@shadowcomputers.co.uk>
The Help & Reference handout now use the plain SmartAoE icon from Roll20's file store as their journal icon (the handout avatar). The icon is set when a handout is created and added to handouts from earlier versions, so existing games get it too.

Roll20 stores the avatar as max.webp with a number, so a handout counts as having the icon when its avatar contains the image's path. Only the webp files exist (thumb.png is a 404), so the URL uses thumb.webp. The root script and the 1.0.3 snapshot stay identical.

Signed-off-by: Steve Roberts <steve@shadowcomputers.co.uk>
…dout

Roll20 always stores a handout's journal icon as the full-size file, whatever size the Mod asks for, and shows that file at its natural size at the top of an open handout. The SmartAoE icon was a 1024 pixel upload, so it filled the handout above the text.

The icon now points at a 100 pixel copy of the same artwork. Handouts from earlier builds are matched on the image path, so they change to the small icon the next time the Mod starts.

The 1.0.3 copy is updated with the script. The version number is unchanged.

Signed-off-by: Steve Roberts <steve@shadowcomputers.co.uk>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants