OK, here is a proof of concept with Muler and ZeroFrame. I'll explain what is going on after the setup and usage.
Setup
- Add a character to hold your Mules, I'll name mine TableMule
- Create a new Ability on TableMule called ActionTable1; paste the following into the text of the ability (then save/close that ability):
0=get.L/get get.K/get
1-4=get.M/get
5-9=get.H/get
10-29=get.C/get
30-49=get.C/get
50-69=get.C/get get.K/get
70-89=get.C/get get.K/get
90-94=get.C/get get.K/get
95-99=get.C/get get.K/get
>=100=get.C/get get.K/get
- Replicate this pattern for Abilities named ActionTable2 through 10, populating with "get" statements of the letters (so a K becomes get.K/get); separate the "get" statements for two letters with a space, as above
- Create a new Ability on TableMule called ArmedResult; paste the following into the text of the ability (save/close):
S={{Scratch=Lose [[1d2]] points, and mark one wound box.}}
L={{Light Wound=Lose [[1d10*2]] points (1d10x2), and mark two wound boxes.}}
M={{Medium Wound=Lose [[2d10*2]] points (2d10x2), and mark three wound boxes.}}
H={{Heavy Wound=Lose [[3d10*2]] points (3d10x2), and mark four wound boxes.}}
C={{Crippling Wound=Lose [[3d10*2]] points (3d10x2), and mark five wound boxes.}}
K={{Knockdown=Defender knocked down and back}}
- Create a new Ability on TableMule called UnarmedResult; paste the following (save/close):
S={{Scant Damage=Lose [[1d2]] points (roll 1d10, 1-5 = 1, 6-10 = 2).}}
L={{Light Damage=Lose [[1d10*2]] points (1d10x2).}}
M={{Medium Damage=Lose [[2d10*2]] points (2d10x2).}}
H={{Harsh Damage=Lose [[3d10*2]] points (3d10x2), and mark one wound box.}}
C={{Crushing Damage=Lose [[3d10*2]] points (3d10x2), and mark two wound boxes (or called shot, if specified otherwise).}}
K={{Knockdown=Defender knocked down and back 5 feet; all uncompleted actions this round are cancelled.}}
Usage
For this example, I am making a couple of assumptions/shortcuts...
- the defensive value (the column to access in your chart -- or, for us, the Mule to read from) is coming from an attribute on the character. I created one called "PacesetterDefAttr" and gave it a non-zero value
- the "Attack Margin" would for you (I'm sure) be a combination of attack attribute, modifier, and roll.... I'm just going with a 1d100 to generate a random result
The command line to use in a macro:
!&{template:default} {{name=@{target|token_name} is Attacked!}} get.[[1d100]].value/get{& mule ActionTable[[{[[ceil(@{target|PacesetterDefAttr}/15)]],10}kl1]].value ?{Type|Armed|Unarmed}Result} {&simple}
Example output:
Kokoro has a PacesetterDefAttr of 13; Armed combat

Igtharian has a PacesetterDefAttr of 87; Unarmed combat

Explanation
We are using the default roll template, and feeding the component rows based on what we return from the table lookups (what we find on our Mules).
To start this as an API-message, we prepend the statement with an exclamation point; to output the roll template at the end, we use the {& simple} tag (from ZeroFrame), which turns the command line into a standard message (no longer an API message). By the time it hits the chat, it will be populated with the roll template parts.
We need to know which ActionTable Mule to look on (1 through 10), as well as whether to look on the ArmedResult or UnarmedResult Mule. We do that with a {& mule ...} statement. {& mule...} statements load those Mules to make the table entries available. Our {& mule...} statement looks like this:
{& mule ActionTable[[{[[ceil(@{target|PacesetterDefAttr}/15)]],10}kl1]].value ?{Type|Armed|Unarmed}Result}
Ultimately, this will say something like:
{& mule ActionTable6 ArmedResult}
- The inline roll takes the PacesetterDefAttr of a targeted token and converts it to a value between 1 and 10. The .value construct extracts the value of the roll (that's a ZeroFrame construct). When that is appended to "ActionTable", you get something like "ActionTable6". Now we know to load "ActionTable6".
- The roll query just asks whether this is "Armed" or "Unarmed". The answer gets prepended to "Result", giving us something like "ArmedResult". Now we know to load the "ArmedResult" Mule.
Finally, the actual variable of the Attack Margin is retrieved from the loaded Mules. Like I said, I'm just generating the margin with a 1d100; you will probably have a larger set of modifiers:
get.[[1d100]].value/get
Since we've only loaded one Mule with numerical values, we get the appropriate result from the ActionTable Mule we loaded. Since that result is further get statements (i.e., get.M/get), we still have work to do.
But we can do ju-jitsu.
ZeroFrame operates on a loop, so the next time it turns to Muler, Muler recognizes that there are new "get" statements it needs to process. This time, we're looking for letter values, which we find in either the Armed or UnarmedResult Mule (whichever we loaded). This time, we load in the roll template parts, which might include new inline rolls:
M={{Medium Wound=Lose [[2d10*2]] points (2d10x2), and mark three wound boxes.}}
...so ZeroFrame rolls those.
Our work is done, so the {& simple} tag instructs ZeroFrame to output the finalized/reconstructed command line as a simple chat message, including the roll tips for the rolls it just processed.

Shabam.