I was introduced to Map Tools about 2 weeks and I found your 4e campaign files. I really like them and they do bring a lot to the "table".
I am using your latest lib:tokens and I came across one error (at least I am experiencing). When you have the health frame open and record any damage/healing/etc it does not update until you close and re-open the frame. I discovered the issue was missing closing </tr> tags in the HeathSelect@LibDice token for the Regain Surges (opening <tr> tag on line 42) and Extened (opening <tr> tag on line 99).
The current version you have is good, but I added some more features that I would like.
Overview of changes:
Updated Character Sheet HP frame for NPC/PC entries
Updated HealthRecord for Death Saving throws.
Update Campaign Properties
First I created a couple more Campaign Properties that will be used by the modified/new macros (included default values):
Code: Select all
HPAbility:Constitution
BaseHitPoints:0
HPPerLevel:0
DeathSaveBonus:0
FailDeathSave:1
I wanted the HP input frame to have separate functions for PCs and NPCs. Also I wanted the PC frame version to allow me to set the base HP, HP per level, and the ability score that is added to the HP total. Also I included a death saving throw bonus, as that can be a separate bonus from normal saving throws, as well as added a flag to indicate whether or not this character can fail Death saving throws. Some races (Warforge) cannot fail a death saving throw. Simply adding a bonus of 10 to the saving throw will not give the correct result (more about that later).
Changes to HPDialog2. I created two macros so I can have two different HP entry boxes, one for PCs and another for NPCs. Also I added the Fail Death Save radio button.
Code: Select all
<!--HPDialog2-->
<!--Straight forward dialog entry. Add to HP overrides the HP box and adds to the previous total. Used NBSP to preserve format. -->
<table border="0" width="100%">
[r, if(isPC() ==1), code:{[r,macro("HPDialog2PC@this"):""]};{[r,macro("HPDialog2NPC@this"):""]}]
<tr bgcolor="FFFFEF"><td>Healing Surge Bonus:</td>
<td>
<input type="text" name="Bonus" value="[r: json.get(HealingSurge, 'Bonus')]" size="4"></input>
</td>
</tr>
<tr bgcolor="EBEBEB"><td>Healing Surges per day:</td>
<td>
<input type="text" name="Surges" value="[r: json.get(HealingSurge, 'Total')]" size="4"></input>
</td>
</tr>
<tr bgcolor="FFFFEF"><td>Saving Throw Bonus:</td>
<td>
<input type="Text" name="SaveBonus" value="[r:Save]" size="4"></input>
</td>
</tr>
<tr bgcolor="EBEBEB"><td>Death Saving Throw Bonus:</td>
<td>
<input type="Text" name="DeathBonus" value="[r:DeathSaveBonus]" size="4"></input>
</td>
</tr>
<tr bgcolor="EBEBEB"><td>Fail Death Save?:</td>
<td>
No:<input type="radio" name="deathsavefail" value="no"[r: if(FailDeathSave==0,"checked","")]></input>
Yes:<input type="radio" name="deathsavefail" value="yes"[r: if(FailDeathSave==1,"checked","")]></input><br>
</td>
</tr>
<tr bgcolor="FFFFEF">
<td>Resistance: </td>
<td>
<input type="Text" name="Resist" value="[r: Resistance]" size="300"></input>
</td>
</tr>
<tr bgcolor="EBEBEB">
<td>Immunity: </td>
<td>
<input type="Text" name="Immune" value="[r: Immunity]" size="300"></input>
</td>
</tr>
<tr bgcolor="FFFFEF">
<td>Vulnerability: </td>
<td>
<input type="Text" name="Vulnerable" value="[r: Vulnerable]" size="300"></input>
</td>
</tr>
<tr>
<td align="center" colspan="2">
<input id="savebutton" type="submit" name="save" value="Save"></input>
</td>
</tr>
</table>
New macro HPDialog2PC. I changed the Hit Points entry box to Base Hit Points, added an entry box for the HP per level value, and added a drop down box for the Ability score that is added to the HP value.
Code: Select all
<!--HPDialog2PC-->
<!--Defines the Hit Points entry area for the PC-->
<tr>
<td bgcolor="black" colspan="2">
<table border="0" width="100%" cellpadding="0">
<tr>
<td>
<span color="white"><b>Base Hit Points:</b></span>
</td>
<td>
<input type="text" name="HitPointBase" value="[r: BaseHitPoints]" size="4"></input>
</td>
<td>
<span color="white"><b> HPs per Level:</b></span>
</td>
<td>
<input type="text" name="LevelHP" value="[r: HPPerLevel]" size="4"></input>
</td>
</tr>
<tr>
<td>
<span color="white"><b>HP Ability:</b></span>
</td>
<td>
<select name="Ability">
[r, foreach(TempAbil, json.fields(AbilityScores), ""), code:{
<option [r: if(HPAbility==TempAbil, "selected ", " ")]value="[r:TempAbil]">[r: TempAbil]</option>}]
</select>
</td>
<td>
<span color="white"><b> Add to total:</b></span>
</td>
<td>
<input type="text" name="HPAdd" value="" size="10"></input>
</td>
<td width="10%"></td>
</tr>
</table>
</td>
</tr>
New macro HPDialog2NPC. Similar to the original HP display, but only has Hit Points entry field. The add to hit points box is not needed.
Code: Select all
<!--HPDialog2NPC-->
<!--Defines the Hit Points entry area for the NPC-->
<tr>
<td bgcolor="black" colspan="2">
<table border="0" width="100%" cellpadding="0">
<tr>
<td>
<span color="white"><b>Hit Points:</b></span>
</td>
<td>
<input type="text" name="HitPointBase" value="[r: HitPoints]" size="4"></input>
</td>
<td width="10%"></td>
</tr>
</table>
</td>
</tr>
Finally modified HPEdit to store it all.
Now calculates the Hit Points using the BaseHitPoint value, selected Ability Score, and the HP per Level.
Code: Select all
<!--HPEdit-->
[h: HPAbility = json.get(macro.args, "Ability")]
[h: BaseHitPoints = json.get(macro.args, "HitPointBase")]
[h: HPPerLevel = json.get(macro.args, "LevelHP")]
[h: TempHPAdd = json.get(macro.args, "HPAdd")]
[h: TemporaryHitPointTotal = BaseHitPoints + json.get(json.get(AbilityScores, HPAbility), 0) + ((Level - 1) * HPPerLevel)]
[h: HitPoints = if(TempHPAdd == "" || TempHPAdd == 0, TemporaryHitPointTotal, HitPoints + TempHPAdd)]
[h: HealingSurge = json.set(HealingSurge, "Value", floor(HitPoints/4))]
[h: HealingSurge = json.set(HealingSurge, "Bonus", json.get(macro.args, "Bonus"))]
[h: HealingSurge = json.set(HealingSurge, "Total", json.get(macro.args, "Surges") + json.get(json.get(AbilityScores, "Constitution"), 1))]
[h: Save = json.get(macro.args, "SaveBonus")]
[h: DeathSaveBonus = json.get(macro.args, "DeathBonus")]
<!--1 means that the character can fail death saving throw, 0 means the character cannot fail a death save-->
[h: FailDeathSave = if(json.get(macro.args, "deathsavefail") == "No", 0, 1)]
[h: Resistance = json.get(macro.args, "Resist")]
[h: Immunity = json.get(macro.args, "Immune")]
[h: Vulnerable = json.get(macro.args, "Vulnerable")]
[h, macro("Sheet@this"): ""]
Edits {token.name}'s health.
Next I updated the HealthRecord and added a new macro HealthSurge from LibDice. As I was talking about the Death Saving Throw earlier, what you had coded is not quite correct. If the modified Die roll is greater than 20, you can spend a healing surge. Currently you have it that you can only spend a healing surge if you roll a 20. Also I added code that would automatically spend a healing surge (if you had one) if you got a 20 or above.
To make things easier (and to promote re-use), I created a new macro to do the HealthSurge.
To that end, I modified the Healing Surge and Death Save portions of the HealthRecord.
Code: Select all
<!--Healing Surge-->
[r, if(Type == "Surge"), code:{
[h, macro("HealthSurge@This"):""][r: macro.return]}; {[r: ""]}]
[r, if(Type == "Death"), code:{
[h: Die = 1d20]
[h: Mod = if(getStrProp(macro.args, "Mod") == "", 0, getStrProp(macro.args, "Mod"))]
[h: ModDeathSave = Die + DeathSaveBonus + Mod]
[h: DeathSave = if(FailDeathSave == 0 && ModDeathSave < 9, 10, ModDeathSave)]
[h, macro("DeathCheck@Lib:Dice"): DeathSave]
Makes a Death Save and... [r: if(DeathSave >9, if(DeathSave > 19, " could get back up!", " remains stable."), if (FailDeathSave == 1, " gets worse ", " remains stable."))] [r: macro.return] ( [r:DeathSave])
[h, if (DeathSave > 19), code:{[macro("HealthSurge@This"):""]}] [r: macro.return]
}; {[r: ""]}]
The new macro, HealthSurge is as follows:
Code: Select all
[h: Amount = if(getStrProp(macro.args, "Amt") == "", 0, getStrProp(macro.args, "Amt"))]
[h: Amt = eval(Amount+"")]
[h: WasBloodied = if(state.Bloodied == 1, 1, 0)]
[h: WasDying = if(state.Dying == 1, 1, 0)]
[h: OrigSurges = json.get(HealingSurge, "Remain")]
[h: SurgeValue = json.get(HealingSurge, "Value") + if(json.get(HealingSurge, "Bonus") == "", 0, json.get(HealingSurge, "Bonus"))]
[h: NoHeal = getStrProp(macro.args, "NoHeal")]
[h: SurgeAmt = if(NoHeal =="Y", 0, SurgeValue)+Amt]
[h: SurgeAmt = if(OrigSurges > 0, SurgeAmt, 0)]
[h: HealingSurge = json.set(HealingSurge, "Remain", max(0, OrigSurges-1))]
[h: CurrentDamage = max(0, if(CurrentDamage > HitPoints, HitPoints, CurrentDamage) - SurgeAmt)]
[h: state.Bloodied=if(CurrentDamage >=round(HitPoints/2) && CurrentDamage < HitPoints && HitPoints >1,1,0)]
[h: state.Dead=if(CurrentDamage >= HitPoints+floor(HitPoints/2),1,0)]
[h: state.Dying=if(CurrentDamage >= HitPoints && CurrentDamage < HitPoints+floor(HitPoints/2),1,0)]
[h: macro.return = if(OrigSurges > 0, " Spends a healing surge and heals " + SurgeAmt + " hit points.", " Tries to spend a healing surge but has none left.")]
I had to compact down the previous output to have it print/return correctly.
You are doing a great job and can't wait to see what is the next feature you add.
JP