Describe the bug
As per our Discord Conversation, the "Create Action" button, when generating code for managing custom counters, has a bug in it with regards to subtracting counters. In several cases you will end up getting (-) numbers in your counter and usually you end up subtracting more than you should and thus have less uses for your abilities based on that counter than you should. Repro steps below.
To Reproduce
Steps to reproduce the behavior:
- Create a Custom Counter, Give it 3 Uses.
- Create an ability that subtracts from that custom counter, give it 1 Cost.
- Run the ability 3 times and note that as you hit 1 use left in the counter and then run it's last use the counter number jumps from 1 to -1 instead of to 0.
Observed
Using counters close to their final uses causes counters to roll over into the negative numbers.
Expected behavior
Counters properly count down by their use cost to 0 and do not go negative.
Desktop (please complete the following information):
- OS & Version: Windows 10 (all OS's)
- MapTool Version: 1.6.1
- MapTool Install type: Fresh 1.6.1
- Framework: Simple5e
Additional context
In the generated code, we find the following:
[h: "<!-- If the token has the counter resources, roll the attack. -->"]
uses {PronounPossessive} Necrotic Shroud (Lasts 1 Minute).
[h: "<!-- Alter the counter and reload Character Sheet if present. -->"]
[h: vCounterMax = json.get(vCounter, "max")]
[h, if(isNumber(vCounterMax)), code: {
[vNewCounterValue = vCounterValue + vCounterCost]
[if(vCounterMax > vNewCounterValue): vCounterCost = vCounterMax - vCounterValue]
};{}]
[h: vCounter = json.set(vCounter, "value", vCounterValue - vCounterCost)]
[h: CustomCounters = json.set(CustomCounters, vCounterIndex, vCounter)]
Take the following case:
- Max Uses: 3
- Current Uses Left: 1 (so 1/3 showing on the character sheet)
- Ability Cost: 1
Line 5: vCounterMax = 3
Line 6: Passes the if Check
Line 7: vCounterValue = 1, vCounterCost = 1, so vNewCounterValue = 2.
Line 8: (This is where the problem occurs). vCounterMax = 3, vNewCounterValue = 2, so vCounterMax > vNewCounterValue. This means vCounterCost = vCounterMax(3) - vCounterValue(1), so vCounterCost = 2...we've just changed the cost of the ability.
Line 9: Closes the If.
Line 10: Resets the vCounter JSON string setting the new "value" to vCounterValue(1) - vCounterCost(2) = -1. Remember that vCounterCost just got updated from 1 to 2 in Line 8.
This skips your counter from 1 to -1, producing the bug.
** Know Fix **
As you noted in Discord, the PROPER code looks like the following:
[h, if(isNumber(vCounterMax)), code: {
[vNewCounterValue = vCounterValue - vCounterCost]
[if(vNewCounterValue > vCounterMax): vCounterCost = vCounterMax - vCounterValue]
};{}]
To fix this for generation:
- Open GM Window
- Right Click on "Create Action" button in the GM Panel
- In the code popup, find line 352 (will be a boatload of HTML String Characters)
- Replace line 352 with the following:
"%0A%09%5Bh%3A+%22%3C%21--+Alter+the+counter+and+reload+Character+Sheet+if+present.+--%3E%22%5D%0A%09%5Bh%3A+vCounterMax+%3D+json.get%28vCounter%2C+%22max%22%29%5D%0A%09%5Bh%2C+if%28isNumber%28vCounterMax%29%29%2C+code%3A+%7B%0A%09%09%5BvNewCounterValue+%3D+vCounterValue+-+vCounterCost%5D%0A%09%09%5Bif%28vNewCounterValue+%3E+vCounterMax%29%3A+vCounterCost+%3D+vCounterMax+-+vCounterValue%5D%0A%09%7D%26semi%3B%7B%7D%5D%0A%09%5Bh%3A+vCounter+%3D+json.set%28vCounter%2C+%22value%22%2C+vCounterValue+-+vCounterCost%29%5D%0A%09%5Bh%3A+CustomCounters+%3D+json.set%28CustomCounters%2C+vCounterIndex%2C+vCounter%29%5D%0A%09%5Bh%2C+if%28isFrameVisible%28token.name+%2B+%22+-+Character+Sheet%22%29+%26%26+hasMacro%28%22Sheet%22%29%29%2C+code%3A+%7B%0A%09%09%5Bmacro%28%22Sheet%40TOKEN%22%29%3A%22%22%5D%0A%09%7D%26semi%3B%7B%7D%5D%0A%7D%5D"]
It and the surrounding lines should look like the following:
(Lines 348 - 356, with line 352 replaced as above)
[h, if(vActionHasCounterCost), code: {
[if(vInfo): log.info("Calculating Custom Counter adustment...")]
[vEncodedCounterCmdA = "%0A%5Bh%3A+%22%3C%21--+Counter+Options+--%3E%22%5D%0A%5Bh%3A+vCounterName+%3D+%22COUNTERNAME%22%5D%0A%5Bh%3A+vCounterCost+%3D+COUNTERCOST%5D%0A%0A%5Bh%3A+%22%3C%21--+Grab+Counter+Info+--%3E%22%5D%0A%5Bh%3A+vCounter+%3D+json.get%28json.path.read%28CustomCounters%2C+%27.%5B%3F%28%40.name+%3D%3D+%22%27+%2B+vCounterName+%2B+%27%22%29%5D%27%29%2C+0%29%5D%0A%5Bh%3A+vCounterIndex+%3D+json.indexOf%28CustomCounters%2C+vCounter%29%5D%0A%5Bh%3A+vCounterValue+%3D+json.get%28vCounter%2C+%22value%22%29%5D%0A%0A%5Br%2C+if%28vCounterValue+%3C+vCounterCost%29%2C+code%3A+%7B%0A%09%5Bh%3A+%22%3C%21--+If+the+token+lacks+the+counter+resource%2C+warn+and+stop.+--%3E%22%5D%0A%09%5Bh%3A+vCounterCategory+%3D+json.get%28vCounter%2C+%22category%22%29%5D%0A%09%5Bh%3A+vCounterMax+%3D+json.get%28vCounter%2C+%22max%22%29%5D%0A%09%5Bh%2C+if%28vCounterMax+%21%3D+%22%22%29%3A+vCounterMax+%3D+%22%2F%22+%2B+vCounterMax%5D%0A%09can%26%2339%26semi%3Bt+do+that%21+%28%5Br%3A+vCounterValue%5D%5Br%3AvCounterMax%5D+%5Br%3AvCounterName%5D+left%2C+need+%5Br%3A+vCounterCost%5D%29.%0A%7D%26semi%3B%7B%0A%09%5Bh%3A+%22%3C%21--+If+the+token+has+the+counter+resources%2C+roll+the+attack.+--%3E%22%5D%0A"]
[vEncodedCounterCmdB =
"%0A%09%5Bh%3A+%22%3C%21--+Alter+the+counter+and+reload+Character+Sheet+if+present.+--%3E%22%5D%0A%09%5Bh%3A+vCounterMax+%3D+json.get%28vCounter%2C+%22max%22%29%5D%0A%09%5Bh%2C+if%28isNumber%28vCounterMax%29%29%2C+code%3A+%7B%0A%09%09%5BvNewCounterValue+%3D+vCounterValue+-+vCounterCost%5D%0A%09%09%5Bif%28vNewCounterValue+%3E+vCounterMax%29%3A+vCounterCost+%3D+vCounterMax+-+vCounterValue%5D%0A%09%7D%26semi%3B%7B%7D%5D%0A%09%5Bh%3A+vCounter+%3D+json.set%28vCounter%2C+%22value%22%2C+vCounterValue+-+vCounterCost%29%5D%0A%09%5Bh%3A+CustomCounters+%3D+json.set%28CustomCounters%2C+vCounterIndex%2C+vCounter%29%5D%0A%09%5Bh%2C+if%28isFrameVisible%28token.name+%2B+%22+-+Character+Sheet%22%29+%26%26+hasMacro%28%22Sheet%22%29%29%2C+code%3A+%7B%0A%09%09%5Bmacro%28%22Sheet%40TOKEN%22%29%3A%22%22%5D%0A%09%7D%26semi%3B%7B%7D%5D%0A%7D%5D"]
[vEncodedCounterCmdA = replace(vEncodedCounterCmdA, "COUNTERNAME", vCounterSelected)]
[vEncodedCounterCmdA = replace(vEncodedCounterCmdA, "COUNTERCOST", vCounterCost)]
[vToolTips = listAppend(vToolTips, "[r: 'Adjusts Counter: " + vCounterSelected + "']")]
};{