Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

Help with custom character sheet

So I want to start off by saying that I am a newbie in HTML and I know next to nothing about how to actually utilize CSS. The project I'm working on is a WIP custom rpg. The goal is to get as close to a simulation as possible while still keeping the pen & paper feel. So Roll20 is the perfect place since I can hide all the complex math work under the hood. As such, you may see me talking about some things not normally used in other Roll20 character sheets. A bit ambitious, I know, but if possible, I'm trying to accomplish it. Now onto my problem. Basically put, I want to display the character's level (a number) as text. I don't mean "one", "twenty", etc, but like "Civilian", "Genin", "Chunin", "Jonin", etc. Also to make things more complicated, I still need there to be an actual numeric value, as some macros and abilities in the game may call for the level to be used as a part of an equation. But I need the player's character sheet to display the word associated with the level instead of said level. If you have any questions or need me to explain anything in detail, let me know. I know I'm asking a lot, and I'm not even sure if this is possible using HTML.
1516092587
Jakob
Sheet Author
API Scripter
Yes, this could easily be done using sheet worker scripts. In essence, your display would be something like <span name="attr_level_title"></span> and you would set the level_title attribute accordingly using a sheet worker whenever the numeric level changes. It could also be done using just CSS and HTML, but it would be pretty convoluted and I would not recommend it.
1516092760
GiGs
Pro
Sheet Author
API Scripter
I suspect you might not realise the magnitude of the project you've set yourself, but good luck! :) There are at least two ways to achieve the desired goal. The first would be a select (dropdown), with visible labels as text, but the hidden values as numbers. Something like: <select name="attr_level" class="sheet-level"> <option value="1">Civilian</option> <option value="2">Genin</option> <option value="3">Chunin</option> <option value="4">Jonin</option> <option value="5">etc</option> </select> Then @{level} will give you the number. That said, you might want to call the label at times too, so you might want a sheet worker. But that will require you to start learning javascript as well as HTML and CSS. By the way, very important:  if you are still designing your game system, I would strongly encourage you to give up on making a character sheet. Just use the Attributes and Abilities tab to set up stats and macros. Once your system is designed, you would then make a character sheet.  If you try to do both at once, it will compromise your system design. You'll lose a lot of time struggling with getting the character sheet to do things you need, then you'll either change your game design forcing you to redo things you are struggling with, or the desire to make the system work with the character sheet you are creating will shape your design in ways you aren't conscious of.
Jakob, would a sheet worker script be an API? If so, I was hoping that this could be done using API. I have no experience with API's but I will definitely learn for this. Also thanks I had no idea "span" was a thing. You just added another tool to my utility belt. I've been using input, value, and disabled to show text on the sheet. And G G, I was thinking about doing a drop-down, but my goal is to have as little as possible be manual. If all else fails, I can do that, but I don't mind this being a longer project. But about waiting till the game is done, I really don't mind having to go back and forth. I'm sort of building it around Roll20 and what it brings to the table that pen & paper can't, so trial, error, and tweaking is kinda what it's all about with this game. I have some rules I've set for myself that act as a sort of "Bill of Rights", if I may, to make sure I never stray too far from the original design. I also have a good friend who helps me test the game as it goes. But I really do appreciate the advice. But thanks both of you for the help. Now on to learn javascript!
1516096383
Jakob
Sheet Author
API Scripter
Alex A. said: Jakob, would a sheet worker script be an API? If so, I was hoping that this could be done using API. I have no experience with API's but I will definitely learn for this. Also thanks I had no idea "span" was a thing. You just added another tool to my utility belt. I've been using input, value, and disabled to show text on the sheet. A sheet worker script is not the same thing as an API script. Sheet workers are (Javascript) code that are part of the character sheet, and they can essentially do just one thing: detect when certain attributes change, and change other attributes in response to that [though in practice this turns out to be pretty flexible]. So, in this example, the sheet worker script would listen to changes for the "level" attribute, and then change the "level_title" attribute in response to that.
1516748874

Edited 1516748906
So I've done some research on writing the script for the sheet worker. I have a working one, but I have a few issues. First is there a way to reference a disable or hidden attribute? When I change the level attribute to disabled to be an auto calculated field, it stops working. I do have a less than ideal fix for now, but my biggest problem is with my inexperience with javascript. So I want to include 'class'. I know that I can insert change:class in the "on" line, but I'm not sure how to include it into the rest of the code. So I am assuming I can change "getAttrs(['level'], function(values)" to "getAttrs(['level', 'class'], function(values)". If I'm wrong about that let me know, but the part I'm really having problem with is the var line. I don't know if I need to figure out how to correctly squeeze class into the same line or if I need to make a new line for class. I'm pretty sure I can figure out how to write class into the else if section, but I could be wrong about that as well. Thanks in advance for any help. <script type="text/worker"> on('change:level change:levelname', function() { getAttrs(['level'], function(values) { var level = parseInt(values.level); if (level == 0) { setAttrs({ levelname: 'Civilian' }); } else if (level == 1) { setAttrs({ levelname: 'Civilian +1' }); } else if (level == 2) { setAttrs({ levelname: 'Civilian +2' }); } else if (level == 3) { setAttrs({ levelname: 'Civilian +3' }); } else if (level == 4) { setAttrs({ levelname: 'Genin' }); } else if (level == 5) { setAttrs({ levelname: 'Genin +1' }); } else if (level == 6) { setAttrs({ levelname: 'Genin +2' }); } else if (level == 7) { setAttrs({ levelname: 'Genin +3' }); } else if (level == 8) { setAttrs({ levelname: 'Genin +4' }); } else if (level == 9) { setAttrs({ levelname: 'Chunin' }); } }); }); </script>
1516749797

Edited 1516749984
GiGs
Pro
Sheet Author
API Scripter
autocalc/disabled fields and sheet workers do not mix at all well. You are best off replacing the autocalc with a sheet worker. You can access hidden attributes fine, but they shouldn't be autocalc/disabled fields. Regarding class, this should work fine (assuming the attributes referenced are not autocalcs: on('change:level change:levelname change:class', function() { getAttrs(['level','class'], function(values) { var level = parseInt(values.level); var class = values.class; PS: you probably don't need change:levelname there, if this function is the only thing that changes levelname. You chould add a sheet:opened to the set of change statements to make sure levelname gets reset if the players accidentally delete it or change it.
So I ended up getting something to work. I'll drop it below. I wish I had the patience to go back and make everything run on sheet workers as opposed to autocalc, but I think I found a good way to get everything working that suits my game's design well while using autocalc and a sheet worker at the same time. But I hadn't seen your reply before I made it, so I never figured out how to do your "var class = values.class;" line. After trying to jam "var class = parseInt(values.class);" repeatedly with no results, I ended up just referencing class by typing out "values.class" every time. But seeing as I didn't have the patience to type out 50 lines for each class, I cut corners by posting this: on('change:level change:class change:levelname', function() {   getAttrs(['level', 'class'], function(values) {     var level = parseInt(values.level);     if (values.class == 'Ninja') {         if (level <= 3) {       setAttrs({ levelname: 'Civilian' });         }        else if (level <= 8) {       setAttrs({ levelname: 'Genin' });         }        else if (level <= 14) {       setAttrs({ levelname: 'Chunin' });         }        else if (level <= 21) {       setAttrs({ levelname: 'Jonin' });         }        else if (level <= 29) {       setAttrs({ levelname: 'Anbu' });         }        else if (level <= 38) {       setAttrs({ levelname: 'Kage' });         }        else if (level <= 48) {       setAttrs({ levelname: 'Sannin' });         }        else if (level >= 49) {       setAttrs({ levelname: 'God' });         }     }          if (values.class == 'Samurai') {         if (level <= 3) {       setAttrs({ levelname: 'Servant' });         }        else if (level <= 8) {       setAttrs({ levelname: 'Ashigaru' });         }        else if (level <= 14) {       setAttrs({ levelname: 'Samurai' });         }        else if (level <= 21) {       setAttrs({ levelname: 'Sohei' });         }        else if (level <= 29) {       setAttrs({ levelname: 'Ronin' });         }        else if (level <= 38) {       setAttrs({ levelname: 'Daimyo' });         }        else if (level <= 48) {       setAttrs({ levelname: 'Tenno' });         }        else if (level >= 49) {       setAttrs({ levelname: 'God' });         }     }          if (values.class == 'Monk') {         if (level <= 3) {       setAttrs({ levelname: 'Samanera' });         }        else if (level <= 8) {       setAttrs({ levelname: 'Navaka' });         }        else if (level <= 14) {       setAttrs({ levelname: 'nissaya-muttaka' });         }        else if (level <= 21) {       setAttrs({ levelname: 'Majjhima' });         }        else if (level <= 29) {       setAttrs({ levelname: 'Thera' });         }        else if (level <= 38) {       setAttrs({ levelname: 'Maha-Thera' });         }        else if (level <= 48) {       setAttrs({ levelname: 'Arhat' });         }        else if (level >= 49) {       setAttrs({ levelname: 'God' });         }     }   }); }); Next I'm planning on adding another part that says if level == 1, 5, 10, etc. listing all the levels with a +1 in front and go on that way. Thanks for all the help.
1516760982

Edited 1516804049
GiGs
Pro
Sheet Author
API Scripter
There's a much shorter way to make your class and level lists, especially if there's exactly 1 name for every level. const classesAndLevels = { Ninja: { 1: "Civilian", 2: "Civilian+1", 3: "Civilian+2", 4: "Civilian+3", 5: "Genin", // and so on up to 50 or whatever your limit is. }, Monk: { // repeat as needed for each class }, }; Put the above code at the start of your sheet worker just after the getAttrs line. And then you can call it with  var level = parseInt(values.level); var class = values.class; var levelName = classesAndLevels[class][level]; setAttr({ levelname: levelName }); So the whole function would be on('change:level change:class change:levelname', function() {   getAttrs(['level', 'class'], function(values) { const classesAndLevels = { Ninja: { 1: "Civilian", 2: "Civilian+1", 3: "Civilian+2", 4: "Civilian+3", // and so on up to 50 or whatever your limit is. // you can spread it over multiple lines for clarity 5: "Genin", 6: "Genin+1", // etc }, Monk: { // repeat as needed for each class }, }; var level = parseInt(values.level); var charClass = values.class; // put some error checking here to make sure class and level are valid var levelName = classesAndLevels[charClass][level]; setAttrs({ levelname: levelName });   }); }); That should work. One thing to be wary of is ensuring that Class and Level are valid values. So I'd recommend using a select input for those, so players cant enter anything invalid, and having a default setup. "morning after" corrections:  there was a typo in setAttrs, and I'd used the word "class" as a variable name, which you can't do. The above code is now tested and works for me.
1516804159
GiGs
Pro
Sheet Author
API Scripter
I had two mistakes in the code in the previous post. They have been corrected.
I didn't see it till after you fixed it so no worries. But thanks, I was just about to write out the rest of it when I read your posts. That's a much better way to handle that. Thanks so much!