Advertisement Create a free account

Auto-subtract Magic Points after a Spell is cast

I have a custom character sheet. In it, we have a spells section. There is an attribute for "magic points" which the player fills in, and another attribute for "magic point cost", which is the cost in magic points to cast the spell. It would be extremely helpful to create a script which can automatically subtract the appropriate number of magic points whenever a spell is cast. Here's how it works: If you successfully cast the spell, you pay the normal amount of magic points. If you fail, you pay half the number of magic points. If you fumble, you pay the full number of magic points. If your magic points reach 0, you pass out and the spell fizzles. What I would like is: every time someone rolls a spell, it automatically deducts the appropriate number of magic points. If casting a spell (whether successfully or not) would result in 0 magic points, get a prompt asking the player "This may cause you to reach 0 MP. Are you sure you wish to cast this spell?" What do I need to do to make this work? Is it just an API script (and if so, could someone be kind enough to provide it as I have no knowledge of JavaScript?) or does it also require HTML/CSS (I can do this to a limited degree, but not much)?
1555094023
GiGs
Pro
Sheet Author
An API script would work, but we cant write it without knowing how  rolls are made, including how each level of success is determined, and relevant attribute names. If the styling should match an existing rolltemplate, that adds extra complications. You can get some of the way there just using an existing script called chatSetAttr (its in the one-click dropdown, in your api scripts section). The trick is identifying the success quality in a way that chatSetAttr can use. The Power Cards API script might also be able to do it - you can find its thread and ask for advice there.
I had a look at those scripts you mentioned but unfortunately I'm not familiar enough with coding in general to figure out a complete way of doing this. As I already have a Roll Template, I'm not sure if the Power Cards is what I'm looking for. I imagine all I would need is to add the appropriate script and then add whatever appropriate chat commands to the roll section of the skill in the HTML. Here's an example of the code for the roll. Note that each Spell is part of a repeating field. <button type="roll" name="roll_SPELL" value="&{template:spell} {{name=@{Name} casts @{SPELL-NAME}}} {{skill_lvl=[[@{SPELL-SKILL}]]}}{{totalmod=[[floor((round(@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0}))-@{SPELL-SKILL}]]}}{{success=[[floor((round(@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0}))]]}}{{half=[[((round((@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0})/2))]]}} {{quarter=[[round(((@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0})/4)]]}}{{thirty=[[floor((round(@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0}))-30]]}}{{sixty=[[floor((round(@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0}))-60]]}}{{crit=[[floor((round((@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0}))/10)]]}}{{fumble=[[90 +floor((round((@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0}))/10)]]}}{{Rolled=[[d100cs<[[floor((round((@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0}))/10)]]cf>[[90 +floor((round((@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0}))/10)]]]]}}"></button> Pardon the mess. I ain't no expert :P. But, you can clearly see the names of the attributes in question. Each school of magic has its own unique repeating section, so things like SPELL-SKILL have been named SPELL-SKILL2 etc. Also I realise the cf > and all that is redundant, but that was there from some previous code and too much effort to get rid of it now. It doesn't do anything anyway. Attribute name for player's current magic points: name="attr_Magic-Points" Attribute name for Spell MP cost (part of a repeating field): name="attr_SPELL-MP" As for the roll template, here it is: <rolltemplate class="sheet-rolltemplate-spell"> <table> <caption>{{name}}</caption> <tr> <td colspan="2" class="template_label">&nbsp;Skill Level:</td> <td class="template_value">{{skill_lvl}}</td> </tr> <tr> <td colspan="2" class="template_label">&nbsp;Total Modifier:</td> <td class="template_value">{{totalmod}}</td> </tr> <tr> <td colspan="2" class="template_label">&nbsp;Value:</td> <!-- <td class="template_value">{{fumble}}/{{success}}/{{half}}/{{quarter}}/{{crit}}/{{thirty}}/{{sixty}}</td> --> <td class="template_value">{{success}}</td> </tr> <tr> <td colspan="2" class="template_label">&nbsp;Rolled:</td> <td class="template_value">{{Rolled}}</td> </tr> <tr style="background:#BEBEBE;"> <td class="template_label">Result:</td> {{#rollBetween() Rolled 1 crit}} <td colspan="2" style="background:Lime;" class="template_value"><b>Critical</b></td> {{/rollBetween() Rolled 1 crit}} {{#rollGreater() Rolled crit}} {{#rollBetween() Rolled crit quarter}} <td style="background:LightGreen;" class="template_value"><b>By Quarter</b></td> {{/rollBetween() Rolled crit quarter}} {{/rollGreater() Rolled crit}} {{#rollGreater() Rolled quarter}} {{#rollBetween() Rolled quarter half}} <td style="background:Green;" class="template_value">By Half</td> {{/rollBetween() Rolled quarter half}} {{/rollGreater() Rolled quarter}} {{#rollGreater() Rolled half}} {{#rollBetween() Rolled half success}} <td colspan="2" style="background:DarkGreen;" class="template_value">Success</td> {{/rollBetween() Rolled half success}} {{/rollGreater() Rolled half}} {{#rollGreater() Rolled success}} {{#rollLess() Rolled fumble}} <td colspan="2" style="background:Crimson;" class="template_value">Fail</td> {{/rollLess() Rolled fumble}} {{/rollGreater() Rolled success}} {{#rollBetween() Rolled fumble 100}} <td colspan="2" style="background:Red;" class="template_value"><b>Fumble</b></td> {{/rollBetween() Rolled fumble 100}} {{#rollGreater() Rolled crit}} {{#rollBetween() Rolled crit sixty}} <td style="background:LightGreen;" class="template_value"><b>&nbsp;&nbsp;&nbsp;-60!&nbsp;&nbsp;&nbsp;</b></td> {{/rollBetween() Rolled crit sixty}} {{/rollGreater() Rolled crit}} {{#rollGreater() Rolled sixty}} {{#rollBetween() Rolled sixty thirty}} <td style="background:Green;" class="template_value"><b>&nbsp;&nbsp;&nbsp;-30!&nbsp;&nbsp;&nbsp;</b></td> {{/rollBetween() Rolled sixty thirty}} {{/rollGreater() Rolled sixty}} </tr> </table> </rolltemplate> Again, not super pretty and there's definitely some things in there that could be better, but it gets the job done (though annoyingly, if you have a skill value of 99 and you roll a 99, it's displayed as both a Success and Fumble instead of just a success. No idea how to fix that) To summarise: Success: roll equal to or less than your Skill value. Deduct full MP cost. Failure: roll more than your Skill value. Deduct half MP cost (rounded up). Fumble: roll 90+(Skill value/10, rounded down). Skill value of 99 is not a fumble if you roll a 99, only a 100. Deduct full MP cost. Is that enough information or do you need more?
1555166643
GiGs
Pro
Sheet Author
Unfortunately, you cant embed an API script command within a rolltemplate. You can output a rolltemplate string from an API script, but in your case, you'll have to do the bulk of the work in the script and simulate the styling. There's no CSS shown so I cant do that. Regarding your rolltemplate showing success and fumble on 99, there are at least two ways to fix that: in the fumble calculation, make sure it's 100, when skill is 99. That looks tricky to get right with your calculation (possible, I'm sure, but extremely clunky) in the roll template, nest the fumble and success check in such a way that if success is true, fumble can not be. The second version should be easier. I think this will work: change this part:                         {{#rollGreater() Rolled success}} {{#rollLess() Rolled fumble}} <td colspan="2" style="background:Crimson;" class="template_value">Fail</td> {{/rollLess() Rolled fumble}} {{/rollGreater() Rolled success}} {{#rollBetween() Rolled fumble 100}} <td colspan="2" style="background:Red;" class="template_value"><b>Fumble</b></td> {{/rollBetween() Rolled fumble 100}} to this                         {{#rollGreater() Rolled success}} {{#rollLess() Rolled fumble}} <td colspan="2" style="background:Crimson;" class="template_value">Fail</td> {{/rollLess() Rolled fumble}} {{#rollBetween() Rolled fumble 100}} <td colspan="2" style="background:Red;" class="template_value"><b>Fumble</b></td> {{/rollBetween() Rolled fumble 100}} {{/rollGreater() Rolled success}} Moving the fumble check inside the rollGreater than success part should mean you cant get them at the same time. This has a problem if your success chance can be over 100, and you can fix that in the success calculation, changing this {{success=[[floor((round(@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0}))]]}} to  {{success=[[ {99,floor((round(@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0}))}kl1]]}} Adding the kl1 group means it will keep the lowest of 99 and the calculated value, hence success will never be 100 or over. I'll come back to the script stuff later.
1555216252

Edited 1555251323
GiGs
Pro
Sheet Author
Here's a script that might fit your needs. It'll print out a roll using your rolltemplate, and include the mp cost, as well as update it on the character sheet. You lose the crit and fumble color coding on the d100 inline roll, but since you have a row that reports whether its a critical or fumble, that shouldn't matter. First, add this to your rolltemplate (maybe make it the last row of the table):         {{#mp_spent}}         <tr>             <td colspan="2" class="template_label">&nbsp;MP Spent:</td>             <td class="template_value">{{mp_spent}}</td>         </tr>         {{/mp_spent}} Change your button code from  <button type="roll" name="roll_SPELL" value="&{template:spell} {{name=@{Name} casts @{SPELL-NAME}}} {{skill_lvl=[[@{SPELL-SKILL}]]}}{{totalmod=[[floor((round(@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0}))-@{SPELL-SKILL}]]}}{{success=[[floor((round(@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0}))]]}}{{half=[[((round((@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0})/2))]]}} {{quarter=[[round(((@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0})/4)]]}}{{thirty=[[floor((round(@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0}))-30]]}}{{sixty=[[floor((round(@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0}))-60]]}}{{crit=[[floor((round((@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0}))/10)]]}}{{fumble=[[90 +floor((round((@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0}))/10)]]}}{{Rolled=[[d100cs<[[floor((round((@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0}))/10)]]cf>[[90 +floor((round((@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0}))/10)]]]]}}"></button> to <button type="roll" name="roll_SPELL" value="!pjspellroll --id:@{character_id} --name:@{name} --spell:@{SPELL-NAME} --level:@{SPELL-SKILL} --cost:@{SPELL-MP} --multiplier:?{Multiplier|1} --modifier:?{modifier|0} --roll:[[1d100]]"></button> And in your API scripts, add this on("ready", () => {      const numberParams = ['level','multiplier','modifier','roll','cost'],     textParams = ['id','name','spell'],     mpname = 'Magic-Points',     mpspent = 'mp_spent',     processInlinerolls = function (msg) {         if (_.has(msg, 'inlinerolls')) {             return _.chain(msg.inlinerolls)                 .reduce(function(previous, current, index) {                     previous['$[[' + index + ']]'] = current.results.total || 0;                     return previous;                 },{})                 .reduce(function(previous, current, index) {                     return previous.replace(index, current);                 }, msg.content)                 .value();         } else {             return msg.content;         }     },     getParameters = function(args) {         const params = args             .map(x => x.split(':').map(y => y.trim()))             .reduce((a, x) => {                 a[x[0]] = x[1];                 return a;               }, {});         return params;     },     getSuccess = params => Math.floor(Math.round(params.level * params.multiplier) + params.modifier*1),     getFumble = params => {         const success = getSuccess(params);         return success > 98 ? 100 : 90 + Math.floor(success/10);     },     buildOutput = function(params) {         let output = `&{template:spell} {{name=${params.name} casts ${params.spell}}} {{skill_lvl=[[${params.level}]]}} `; //&{template:spell}          const success = getSuccess(params);         const fumble = getFumble(params);         const crit = Math.round(success/10);                  output += `{{totalmod=[[${success}-${params.level}]]}} `;         output += `{{success=[[${success}]]}} `;         output += `{{half=[[${Math.round(success/2)}]]}} `;         output += `{{quarter=[[${Math.round(success/4)}]]}} `;         output += `{{thirty=[[${success -30}]]}} `;         output += `{{sixty=[[${success -60}]]}} `;         output += `{{crit=[[${crit}]]}} `;         output += `{{fumble=[[${fumble}]]}} `;         output += `{{Rolled=[[${params.roll}]]}}`;         output += `{{${mpspent}=[[${getSpent(params)}]]}}`;         return output;     },     getSpent = function(params) {         const success = getSuccess(params);         const fumble = getFumble(params);         let cost = params.cost;         if(params.roll > success && params.roll < fumble) cost = Math.ceil(cost/2);         return cost;     },     updateCost = function(params) {         const cost = getSpent(params);         const mp = findObjs({                                           _characterid: params.id,                                           name: mpname,                                   })[0];         if(mp) {             let current = mp.get('current');             current -= cost;             mp.set('current',current);         };     };          on("chat:message", msg => {         if(msg.type == "api" && msg.content.match(`!pjspellroll --`)){             const msg_new = processInlinerolls(msg);             const args = msg_new.split('--');             args.shift();             const params = getParameters(args);             const output = buildOutput(params);             sendChat('character|' + params.id,output);             updateCost(params);         }     }); }); CAVEATS: I dont have error checking, so if there are typos in the button code or missing attributes or attributes with invalid values, it can crash the script sandbox, and scripts will stop working till you manually restart that. But since you are calling this from a character sheet, that shouldn't happen very often. I'll add it later if you like this script, but it's bedtime for now.
Cheers for the code. I've been testing it for the past 15 min. It appears to be working but there is one major bug and one missing feature. Whenever a roll is made, it multiplies the Skill by 10 no matter what. Even if you make absolutely sure that the Multiplier box is set to 1, it still multiplies it by 10 (or 20 if the multiplier is set to 2, etc). I couldn't figure out what in the script is causing that (curse not having any JavaScript knowledge). The second thing is that it doesn't appear to be automatically subtracting the character's current Magic Points. It's displaying the correct number of magic points to be deducted at the end of the roll, but it's not getting updated in the character sheet. I noticed in the script there is no mention of the attribute "Magic-Points", which is what the name of the attribute where the character's current magic points are stored is called. I figured it might be easier for you to see the entire code, so I've uploaded it to Pastebin. Here you are (this is with your current changes. Excuse the mess): HTML:  https://pastebin.com/i0WGH7b2 CSS :  https://pastebin.com/7ejqK4Wq You may notice that in the spells section there are several different Spell Schools each with their own unique attribute names. I figured I would need to just create a script for each of them with the appropriate attribute names, which shouldn't be that difficult. Only the first Spell school has the button change – the rest are unchanged.
1555250646

Edited 1555250738
GiGs
Pro
Sheet Author
PotatoJedi said: Cheers for the code. I've been testing it for the past 15 min. It appears to be working but there is one major bug and one missing feature. Whenever a roll is made, it multiplies the Skill by 10 no matter what. Even if you make absolutely sure that the Multiplier box is set to 1, it still multiplies it by 10 (or 20 if the multiplier is set to 2, etc). I couldn't figure out what in the script is causing that (curse not having any JavaScript knowledge). How is the success chance calculated? i thought I'd copied it from your formula but I may have misunderstood.  Edit: oh, I think I know what's happening, will be an easy fix. The second thing is that it doesn't appear to be automatically subtracting the character's current Magic Points. It's displaying the correct number of magic points to be deducted at the end of the roll, but it's not getting updated in the character sheet. I noticed in the script there is no mention of the attribute "Magic-Points", which is what the name of the attribute where the character's current magic points are stored is called. That's an easy fix, I misread the magic point attribute name. Near the top of the script is this line mpname = 'SPELL-MP', change it to  mpname = 'Magic-Points', I figured it might be easier for you to see the entire code, so I've uploaded it to Pastebin. Here you are (this is with your current changes. Excuse the mess): HTML:  https://pastebin.com/i0WGH7b2 CSS :  https://pastebin.com/7ejqK4Wq You may notice that in the spells section there are several different Spell Schools each with their own unique attribute names. I figured I would need to just create a script for each of them with the appropriate attribute names, which shouldn't be that difficult. Only the first Spell school has the button change – the rest are unchanged. Regarding the spell schools, it would be easier to pass the attribute names to the script in the button value, instead of making separate copies of the script. Which are the attributes that vary between schools, and what are they in each school?
1555251399
GiGs
Pro
Sheet Author
I've edited the script above to fix the magic-points stat and the multiplying by 10 problem. Now we just need to know what details need tweaking for each magic school. What varies between the schools?
1555259190

Edited 1555259250
GiGs
Pro
Sheet Author
In your repeating_spells section, I'd also suggest changing the spell_skill from an input to a select. Change                     <div class="spells-skill-row inline" style="width: 45.5px">                         <input type="text" value="@{Learn}" style="width: 45.5px;" name="attr_SPELL-SKILL" />                     </div> To                     <div class="spells-skill-row inline" style="width: 45.5px">                         <select style="width: 45.5px;" name="attr_SPELL-SKILL" /> <option value="@{Learn}" selected>Learn</option> <option value="@{Essence}">Essence</option> <option value="@{Willpower}">Willpower</option> </select>                     </div> I'm guessing at what attributes should be in there, but you get the idea. Having a dropdown is much safer than relying on players to enter the correct text without typos. I could also advice changing all your styles to classes in css, but thats a big job and not relevant to the problem at hand. I'd suggest looking into that though in the future.
1555283724

Edited 1555334321
Going to test these in a bit. Just wanted to answer the questions you asked. Pretty much every single attribute in the schools is different (ending in a number), but the attributes which are relevant to the roll are: SPELL-NAME SPELL-SKILL SPELL-MP Not sure if the name of the roll button is relevant, but if it is, it's: roll_SPELL I've literally just made several sections for loads of different Spell Schools and assigned each of them a unique attribute (SPELL-NAME, SPELL-NAME-2, etc) because I have no idea how to give myself less work to do. Anyway, is that the information you were looking for or something else? As for the drop down menu, it needs to actually be a text box because the way the system works is that if you have no skill in a Skill, then it uses your Learn value instead. That's what the @{Learn} is. Originally I wanted to make that text "translucent" (similar to placeholder text) so that when a player types in the field, it doesn't register that text as actually being there and will be overwritten with whatever the player adds. Unfortunately I couldn't figure out how to do that and still have the @{Learn} function as is, so I just left it there and told players what that text was for. Once a skill goes up, the player just deletes the @{Learn} and enters the new value. Yes. CSS would have made things a lot easier, but I was still very new (and still am) to coding and haven't thought of that when I was butchering the sheet from another one.
1555286662
GiGs
Pro
Sheet Author
For those other schools you should be avble to reuse the same button code, and change one section. In this code below, just change each mention of SPELL-SKILL to SPELL-MP, SPELL-NINE, or whatever.  <button type="roll" name="roll_SPELL" value="&{template:spell} {{name=@{Name} casts @{SPELL-NAME}}} {{skill_lvl=[[@{SPELL-SKILL}]]}}{{totalmod=[[floor((round(@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0}))-@{SPELL-SKILL}]]}}{{success=[[floor((round(@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0}))]]}}{{half=[[((round((@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0})/2))]]}} {{quarter=[[round(((@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0})/4)]]}}{{thirty=[[floor((round(@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0}))-30]]}}{{sixty=[[floor((round(@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0}))-60]]}}{{crit=[[floor((round((@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0}))/10)]]}}{{fumble=[[90 +floor((round((@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0}))/10)]]}}{{Rolled=[[d100cs<[[floor((round((@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0}))/10)]]cf>[[90 +floor((round((@{SPELL-SKILL}*?{Multiplier|1})+?{Modifier|0}))/10)]]]]}}"></button>
Tested everything and it appears to be working! Thanks a bunch for your help Mr GiGs. Now I just need to update the button code for all the different schools but that shouldn't take too long. No idea what voodoo magic you did to make the script work with all the different attribute names, but hey, I'm not complaining.
1555373116
GiGs
Pro
Sheet Author
I'm happy its working :) Regarding that dropdown suggestion, I think you are still better switching to it. You could hardcode the possible values like this: <div class="spells-skill-row inline" style="width: 45.5px">                         <select style="width: 45.5px;" name="attr_SPELL-SKILL" /> <option value="@{Learn}" selected>Default</option> <option value="0">0</option> <option value="1">1</option>                                 <option value="2">2</option>                                 <option value="3">3</option> </select>                     </div> Just enter an option for each possible value