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

First Sheet Complete - Unity!

I did it! Been stumbling all over myself for months trying to get the basics of HTML and CSS, but now I think this is finally in satisfying shape.  This is a mostly-original sheet for Unity by Zensara Studios, a neat post-apocalyptic semi-steampunk fantasyscape which was Kickstarted in 2016 and currently has... zero playable adventures.  But it's definitely fun!  I very loosely based the sheet on Alain H. Kirsty's Tales from the Loop sheet, but I think you'll see the end product spun off in a very different direction. I know my sheet isn't going to be allowed as an official sheet in its current form.  That's fine.  I realized halfway through that the fun I wanted to have with sheet workers was impermissible under Roll20's rules for official sheets, so I am content to make a sheet that works for my gaming crew, and which others can enjoy if they like.  For example, the sheet loads in a bevy of stats and starting abilities when the player picks their race and class.  It also brings up handy advancement tables at the bottom based on the characters' class, so players know what to do when they level up (it's complicated).  In its current form I am running it with some companion scripts, which is another reason it won't work for everybody... The main reason I had to go the scripting route is because I wanted custom FX to go along with corresponding button abilities (so when you roll your Holy Smite or Black Blood from the sheet, you get the proper FX).  Outside of the FX there is nothing else going on in API, so I can definitely provide a version with the original non-script button commands if people like. There's also a single rollable table that goes with it, since the game's "fading" mechanic has you roll against a unique weighted table of outcomes which are pretty tough to remember without a handy guide.  Goals for sharing: See if anyone has helpful quick tips on styling See if the layout makes sense Gather suggestions Look for obvious things that I missed/ don't know how to do Thoughts are greatly appreciated.   (I really really want a different font, and I guess I'm just waiting on the new font feature to come in.  None of the usable ones really fit this game). So - THE SHEET! HTML CSS ' The top really has all the good stuff.  I really like how the core attribute and HP section came out.  Highlights: The die roll buttons for "Recupes" and "Recharge" are actually linked to class choice (ranging from d4 to d10, and I successfully made them alter appearance based on the player's input. The big ruler-like scale on the left is for a resource unique to each class.  All the buttons are clickable and have a hover/ transition glow.  It is auto-set to the class' max value. (It's kind of odd, I know, but I made it to mirror the sheet in the core book.) The "Fading" skulls turn red as the player is dying - if they're all red, you dead. This took forever - the buttons on the Features and Powers are complicated, and they convey a lot of information.  Notice the array of letters under the name - they light up to indicate what kind of action the ability is.  The green checkmark can switch to red on a click to show that the ability is no longer usable until a Rest.  And the ornate emblem button posts the power in a template in the chat. I like the money and gear section on the right... It's a fun  shape. The armor section is also kinda charming, I think. The Racial and Class Features auto-populate all fields at character creation. More Powers (specifically the player's chosen Powers).  These ones have the linked FX which you can see in the text box below their descriptions.  Note the fun button for weapon rolls There is a second resource tracker for some classes with multiple resources. Then the sheet calls an advancement table at the bottom based on your chosen class! (there's more below this, but you get the idea).
1585287181

Edited 1585287445
GiGs
Pro
Sheet Author
API Scripter
Nice work! I'm not 100% sold on the color scheme, but it's impressive work. Since you asked for suggestions, i had a look at the sheet workers, and want to make some observations and suggestions for one of them. The one that starts on("change:might", function () {     getAttrs(["might", "recupes_max", "recupes", "needs_max", "gear_max"], function (values) {         setAttrs({             "recupes_max": 2 + (Math.floor(values.might / 2)),             "recupes": 2 + (Math.floor(values.might / 2))         }); The first observation: your script sets  the values of recupes, needs_max, etc. But it never actually reads  them from the sheet. So you dont need them in the getAtrrs line. That should be       getAttrs ([ "might" ],  function  ( values ) { You only need to "get" the "attrs" that you actually read from the sheet. This one's more important: its best practice to only have one getAttrs and one setAttrs per sheet worker. Each time you call one of these introduces a little slow down, and enough of them can add up. There's another problem with it - that isn't relevant to this sheet, but it can become one if you get comfortable writing scripts this way you can easily fall afoul of it by habit. So its best avoided: and that is setAttrs commands are asynchronous, which means they dont necessarily happen in the order they are written. This can be an issue if you arent careful - sometimes you can get the wrong value if you do things in a different order. So if you're in a situation were you want to setAttrs more than once, its better to learn the technique of saving the attribute changes you want to make to a variable, that you then later save all in one go. For that, instead of this: setAttrs({             "recupes_max": 2 + (Math.floor(values.might / 2)),             "recupes": 2 + (Math.floor(values.might / 2))         }); do this const output = {}; output.recupes_max = 2 + (Math.floor(values.might / 2)); output.recupes = 2 + (Math.floor(values.might / 2)); I'd also add that since you are using values.might multiple times, it is better to save that into a variable first. You can then do some error checking on it. So the above would become const output = {}; const might = Math.floor( (+values.might||0) /2); output.recupes_max = 2 + might; output.recupes = 2 + might; Notice in the might declaration i did this: (+values.might||0) This is to coerce it into a number, and if its not recognised as a number, set its value to 0. That way the worker doesnt crash when a non-numeric value is entered. Okay, with your attributes in this form, how do you do setAttrs? That's simple: instead of  setAttrs({             "recupes_max": 2 + (Math.floor(values.might / 2)),             "recupes": 2 + (Math.floor(values.might / 2))         }); just do setAttrs(output); The output variable replaces the contents if the above setAttrs, and furthermore, if you add other stuff to output first, it works without changes. On to the rest of your worker. You have a bunch of if statements like this:         if (values.might == -2) {             setAttrs({                 "needs_max": 1,                 "gear_max": 4             });         }         if (values.might == -1) {             setAttrs({                 "needs_max": 2,                 "gear_max": 5             });         } Since we want to avoid multiple setAttrs statements, we can change that to         if (might === -2) {             output.needs_max: 1;             output.gear_max": 4;         } else if (might === -1) {             output.needs_max: 2;             output.gear_max: 5;         } And so on. Note how setting might as a variable earlier is saving typing now. Also I changed the == to ===. This is an equals that only works if the data is the same type  - but we have already set might as an integer earlier, so we know it always will be. Its better practice to use === when you can, it helps avoid certain subtle errors and can expose others. Notice also that I added an else statement after each if.  This is for efficiency purposes. In javascript, the code stops at the first matched element, and skips the rest of the linked code. Without the else, those are separate, independent statements, and javascript will always check them all. Even when its not necessary. With the else  statement, it skips the rest once it has matched one. Another thing I noticed: at the start of your function, you have if (values.might == -2) {             setAttrs({                 "needs_max": 1,                 "gear_max": 4             });         }         And at the end you have if (values.might == -2) {             setAttrs({                 "needs_max": 7,                 "gear_max": 13             });         } You are checking for might of -2 both times, and setting different values. I have no way of knowing which is correct but you code will set them both, and because of asynchronicity, there's no way of predicting which one will happen last. Putting that all together, the worker (with only the first 3 parts of the if statement) would look like this: on("change:might", function () {     getAttrs(["might"], function (values) {         const output = {};         const might = Math.floor( (+values.might||0) /2);         output.recupes_max = 2 + might;         output.recupes = 2 + might;         if (might === -2) {                 output.needs_max = 1;                 output.gear_max = 4;         } else if (might === -1) {                 output.needs_max = 2;                 output.gear_max = 5;         } else if (might === 0) {                 output.needs_max = 3;                 output.gear_max = 6;         }         setAttrs(output);     }); }); Hope that helps!
1585310602
Andreas J.
Forum Champion
Sheet Author
Translator
Ryan B. said: I know my sheet isn't going to be allowed as an official sheet in its current form.  That's fine.  I realized halfway through that the fun I wanted to have with sheet workers was impermissible under Roll20's rules for official sheets, so I am content to make a sheet that works for my gaming crew, and which others can enjoy if they like.  For example, the sheet loads in a bevy of stats and starting abilities when the player picks their race and class.  It also brings up handy advancement tables at the bottom based on the characters' class, so players know what to do when they level up (it's complicated).  In its current form I am running it with some companion scripts, which is another reason it won't work for everybody... The main reason I had to go the scripting route is because I wanted custom FX to go along with corresponding button abilities (so when you roll your Holy Smite or Black Blood from the sheet, you get the proper FX).  Outside of the FX there is nothing else going on in API, so I can definitely provide a version with the original non-script button commands if people like. If you reach out to the publisher and they would happen to approve your sheet with the existing levelling info and race presets, there probably shouldn't be any issue, unless the sheet requires API to function. (But it wouldn't be impossible that the restriction could be vaived of you have the approval of the publisher, it's worth a shot asking Roll20.)